
The Ugly Truth About dev.to's Dead Support System | 👊
Hanzla Baig ・ May 21
Git is a distributed version control system (DVCS) originally created by Linus Torvalds. It lets multiple developers collaborate by tracking every change in your code history. Each developer has a full copy of the repository, enabling offline work and fast merges. Git is known for its speed, flexibility, and open-source community support. Every commit in Git records the author’s name and email, so you should configure these right after installing Git. Below is a comprehensive guide covering Git’s installation, configuration, and every major command, from basics to advanced tips.
Git’s architecture: The diagram above illustrates Git’s design: your working directory (red) holds your files, changes are staged into the index/cache (yellow), and committed into your local repository (green). You then synchronize with a remote repository (blue) on platforms like GitHub or GitLab. This flow (working → staging → commit → remote) is the heart of Git’s workflow.
🖥️ Installation & Setup
Before using Git, install it on your OS of choice. On Linux you can use the package manager: e.g. sudo apt install git-all
(Debian/Ubuntu) or sudo dnf install git-all
(Fedora/RHEL). On macOS, Git comes with Xcode command-line tools (running git --version
prompts installation), or download the latest installer from git-scm.com. On Windows, download Git for Windows from the official site or use package managers like Chocolatey.
Once installed, configure your identity (one-time, globally):
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
This attaches your name/email to all future commits, and cannot be changed per commit later. You can also set defaults like your preferred text editor (core.editor
) or enable color output (color.ui auto
) with git config
. For cross-platform line-ending consistency, set core.autocrlf
: on macOS/Linux use git config --global core.autocrlf input
, and on Windows use git config --global core.autocrlf true
. This converts CRLF to LF on commit/push, avoiding messy diffs.
Additionally, create a .gitignore
file in your repo root to exclude generated or sensitive files. You might also create useful aliases, e.g., git config --global alias.st status
for shorthand. Many teams require signed commits or specific username/email formats—check your organization’s guidelines.
📦 Git Basics (Creating and Saving)
-
git init
– Initialize a repository. Run this in a project folder to start tracking it with Git:
git init
This creates a new .git
directory. It’s the very first command in versioning a project.
-
git clone [url]
– Clone from remote. Copies an existing repository (and its history) to your local machine:
git clone https://github.com/user/my-project.git
This creates a new folder with the project, and a remote
named origin
pointing to that URL. Now you can work offline with a full copy.
-
git status
– View changes. Shows which files are modified, staged, or untracked:
git status
Always run this before committing or switching branches to see your work-in-progress.
-
git add [file...]
– Stage changes. Moves changes from the working directory into the staging area:
git add file1.txt
git add . # stage all changes in current folder
Staging prepares a “snapshot” of your files for the next commit.
-
git commit -m "message"
– Record changes. Takes staged changes and saves them as a new commit in history:
git commit -m "Fix bug in user login"
Each commit should have a clear message. Commits are atomic units of work (one fix or feature per commit). After committing, your staging area is cleared until you git add
again.
-
git log
– View history. Shows the commit history (latest on top) of the current branch:
git log
Combine with options (like --oneline
, --graph
, or date formats) to filter or format output. git log
is often used with git blame
or git bisect
during troubleshooting (see below).
-
git diff
– Inspect changes. Compare file differences between commits, branches, or the working directory. For example,git diff
(with no args) shows unstaged changes, andgit diff --staged
shows staged but uncommitted changes. You can also dogit diff HEAD~1 HEAD
to see the difference between the last two commits. Example:
git diff # unstaged changes
git diff --staged # changes staged for commit
The output highlights lines added (green) or removed (red). If you ever need to review what will be included in a commit, use git diff
to make sure nothing surprising is happening.
-
git rm
,git mv
,git rename
– Remove or rename files.-
git rm file.txt
removes (and stages removal of) a tracked file. -
git mv old new
renames a file (or move it to a new location) in one step. These update both the working directory and staging area.
-
🔀 Branching & Merging
Git’s power shines with branches. A branch is a movable pointer to a series of commits, used to isolate development. Branches create independent lines of work. Use git branch [name]
to list or create branches, and git checkout [branch]
(or git switch [branch]
) to switch context. For example:
git branch feature/login
git switch feature/login # or `git checkout feature/login`
Now you can work on the feature/login
branch without affecting main
. When ready, merge back into your main branch.
Branching diagram: The figure above shows how a feature branch (magenta) diverges from master
and is later merged back. Note how the feature/signup branch’s commits (purple) merge into master
without disturbing each other. Branching lets multiple features (or developers) progress in parallel.
-
git branch
– Manage branches.-
git branch
lists all local branches, highlighting the current one. -
git branch <name>
creates a new branch off the current commit. -
git branch -d <name>
deletes a branch. This is your general-purpose branching tool.
-
-
git checkout
/git switch
– Change branches or restore files. Traditionally,git checkout
has two roles (switch branch, or restore files). Git 2.23+ introduced specialized commands:-
git switch <branch>
safely moves to an existing branch orgit switch -c <new-branch>
to create+switch. -
git restore <file>
reverts changes in the working directory (discard modifications). Example:
-
git switch develop # move to branch 'develop'
git switch -c hotfix/1.0.1 # create and switch to new branch
These make it clearer: git switch
is for branch changes, git restore
for undoing file edits. (Behind the scenes, these use the same mechanisms as git checkout
.)
-
git merge <branch>
– Merge another branch into current. To combine changes from a branch into your active branch:
git switch main
git merge feature/login
This finds the common ancestor and creates a new merge commit (unless it can fast-forward). Merge commits have two parents (one from each branch). Merging preserves the full history, making it clear when and why branches integrated. If conflicting changes exist, Git will pause for you to resolve them manually. After resolution, git add
the fixed files and git commit
to complete the merge.
Fast-Forward vs. No-FF: If
main
hasn’t moved since branching,git merge
will simply move themain
pointer forward (fast-forward). For record-keeping, usegit merge --no-ff feature/login
to always create a merge commit even when fast-forwarding.-
git fetch
&git pull
– Sync with remote. First, add a remote withgit remote add origin <url>
(typically done duringgit clone
). Then:-
git fetch
downloads new commits and branches from the remote, but doesn’t merge them. -
git pull
is essentiallygit fetch
plusgit merge
(or--rebase
) of the remote branch into your local one:
git fetch origin git merge origin/main # or simply git pull origin main
-
Use pull
to update your branch with upstream changes. Some teams prefer git pull --rebase
to linearize history.
Multi-branch scenario: In this example, multiple developers (you, “Sarah”, “Max”) each create their own branches. Sarah’s and Max’s work (yellow and green, respectively) start from master
and diverge. When each is ready, they merge back into master
. Each merge can be done with git merge
or via pull requests on platforms like GitHub/GitLab, enabling code review.
📚 Intermediate Workflows
Forking Workflow: On platforms like GitHub, you often fork a repository (create your own copy online), clone your fork locally, work there, and then open a Pull/Merge Request to upstream.
git remote add upstream <original_repo>
lets you pull changes from the original repo. Then usegit fetch upstream
andgit merge upstream/main
(orrebase
) to stay up-to-date.Gitflow & Branch Models: Large projects often follow structured workflows. Gitflow uses dedicated branches for
develop
,feature/*
,release/*
,hotfix/*
. For example, create a feature branch offdevelop
, thengit merge
intodevelop
when done, and later release branches get merged intomain
. Alternatively, feature-branch workflow means each feature gets its own branch and is merged intomain
via pull request. Choose one strategy and stick with it, documenting it for your team.Stashing – If you’re midway on some work but need to switch contexts,
git stash
temporarily shelves your uncommitted changes:
git stash # saves and reverts changes
git switch other-branch
# ... work on something else ...
git switch - # back to previous branch
git stash pop # re-apply stashed changes
This is handy for preserving a clean working directory while you address urgent work.
🔧 Undoing Changes & History Editing
-
git reset
– Unstage or move HEAD. With no options,git reset <file>
unstages changes (moves from index back to working directory). With flags:-
--soft
moves the HEAD pointer to a previous commit but leaves all changes staged. -
--mixed
(default) unstages changes but keeps them in working dir. -
--hard
resets everything (HEAD, index, working dir) to the specified commit. Usegit reset
with caution: it rewrites history and discards commits if they were not pushed.
-
git revert
– Safe rollback. Unlikereset
,git revert <commit>
creates a new commit that undoes the changes of the given commit. This is the recommended way to “undo” a public commit, as it preserves history. Example:
git revert abc123 # creates a new commit that reverses commit abc123
git clean
– Remove untracked files. If you have new files you don’t want,git clean -f
deletes them from the working directory. Useful for cleaning build artifacts. (Add-d
to remove untracked directories, and use-n
to preview).git commit --amend
– Edit last commit. If you just committed but forgot something, use:
git add missing_file
git commit --amend
This replaces the previous commit with a new one (including your new changes or updated message). Be very careful: amending rewrites history. Only amend commits not yet pushed (or be prepared to force-push and coordinate).
-
git rebase
– Move or combine commits. Rebasing reapplies commits from one branch onto another, creating a linear history. For example, to incorporate upstream changes into your feature branch:
git switch feature
git fetch origin
git rebase origin/main
This moves your feature
branch commits to start from the tip of main
. Benefits: a clean, linear history (no merge commits) and easier git log
bisecting. Golden Rule: never rebase public/shared branches (it rewrites history others may rely on).
Interactive rebase: git rebase -i HEAD~n
lets you squash, reorder, or edit commits. This is powerful for cleaning up series of small commits before merging. For example, pick
, squash
, fixup
commands in the rebase todo can merge multiple commits into one.
-
git cherry-pick <commit>
– Copy a commit. Applies a single commit from another branch onto your current branch. For instance, ifmain
has a bugfix commit you need indevelop
:
git switch develop
git cherry-pick abc123
This reapplies commit abc123
(from anywhere) as a new commit on develop
.
-
git stash branch <branch>
– Create a new branch and apply stash in one step:
git stash branch new-feature
-
git submodule
– Include external repos. If your project depends on another Git repo, use submodules (though many prefer alternatives). For example:
git submodule add https://github.com/lib/project.git libs/lib-project
This creates a .gitmodules
file tracking a specific commit of that repo. Submodules are fixed to a commit and do not auto-update. Use them when you need strict version control over an embedded dependency.
-
Other advanced commands:
git bisect
(binary search to find a bad commit),git reflog
(recover lost commits by looking at reference logs),git blame
(see who last modified each line),git cherry
(find commits not merged),git filter-repo
orgit filter-branch
(rewrite history globally, e.g., remove a password from all commits). Each of these has powerful use-cases:-
git bisect
automates a binary search through commit history to isolate the exact commit that introduced a bug. -
git reflog
shows all moves ofHEAD
, enabling you to recover "lost" commits (for example, after an accidentalreset
). -
git blame
annotates each line of a file with the last commit and author that changed it, great for tracking origin of code.
-
git tag
– Tag a commit. Mark a specific commit, often for releases. Lightweight tags (git tag v1.0
) or annotated tags (git tag -a v1.0 -m "Release 1.0"
). You can push tags withgit push origin --tags
.
🤝 Collaboration & Team Workflows
Git shines in team settings, but good habits matter:
Commit small, atomic changes. Follow best practice: “make incremental, small changes” and keep commits atomic (one fix/feature per commit). This makes code review and rollback easier.
Descriptive commit messages. Write messages in imperative present tense (e.g., “Add user login validation” not “Added”) and clearly explain why a change was made. A good message helps teammates and your future self understand the context.
Branching strategy. Agree on a workflow: centralized (everyone commits to
main
directly), feature-branch (one branch per feature, then PR merge), GitFlow (withdevelop
/release
branches) or personal branches. Document it so everyone follows the same approach. For example, do you squash commits on merge, or keep full history? Set branch protection rules on the remote (require reviews, forbid force-push tomain
, etc.).Code reviews and pull requests. Always get feedback via PRs/MRs before merging to
main
. Code reviews improve quality and share knowledge. Set up CI tests on PRs to catch issues early.Regular syncing. Frequently
git pull --rebase
(or merge) to incorporate teammates’ changes into your branch. The more often you sync, the fewer conflicts accumulate. If working long-lived branches, consider rebasing often to keep history tidy.Cross-platform tips: Windows users should be mindful of line endings and path length issues. We mentioned
core.autocrlf
above. Also, Unix permissions (executable bits) don’t always translate to Windows—use.gitattributes
to manage differences. Git Bash or WSL on Windows mimics Unix-like behavior for commands.Git Hooks: Teams often use Git hooks to enforce policies (e.g., pre-commit to run linters, pre-receive on server to enforce commit message format). Explore
.git/hooks
or tools like Husky to automate checks.Git LFS: For large binary files (assets, media), use Git Large File Storage (LFS) so you don’t bloat the repo. It replaces big files with pointers.
Backup and Remote: Always push to a shared remote (GitHub/GitLab/Bitbucket). This acts as offsite backup (every clone is a backup copy). Enable branch protection or require signed commits if your org needs high security.
-
Custom Tools and GUIs: While Git CLI is powerful, many teams use GUIs. Examples:
- GitHub Desktop (cross-platform, free) – basic commit/branch GUI.
- Sourcetree (free, Atlassian) – visualizes branches and commits.
- GitKraken, SmartGit, Tower – commercial clients with advanced features.
- TortoiseGit – Windows Explorer integration.
- Built-in IDE integrations (VSCode, IntelliJ, etc.) also provide visual diff/merge tools. These tools wrap underlying Git commands (so all CLI knowledge still applies), but offer graphical convenience.
🛠️ Debugging & Troubleshooting
Merge conflicts: When a merge or rebase stops at a conflict, Git marks the conflict in files. Edit the files to resolve (look for
<<<<<<<
markers), thengit add
the resolved files andgit commit
(orgit rebase --continue
). Usegit merge --abort
to undo a merge in progress, orgit rebase --abort
to cancel a rebase.git bisect
– to find a bad commit:
git bisect start
git bisect bad # current version has the bug
git bisect good v1.2.3 # a known good older tag/commit
Git will checkout a mid-point commit; test your code and then run git bisect good
or git bisect bad
. Repeat until Git pinpoints the exact commit that introduced the issue. This is invaluable for regression hunting.
Recovering lost commits: If you thought you lost work (e.g., after a bad reset), use
git reflog
to list whereHEAD
has been. You can oftengit reset
back to a commit hash shown inreflog
to recover. Think ofreflog
as undo history.git blame
– Find origin of code. Rungit blame file.txt
to see who last modified each line in a file. Useful to identify when/why a bug was introduced. Many hosting services (Bitbucket/GitHub) show blame info graphically in the UI.Network issues: If
git push
is rejected due to conflicts or non-fast-forward, pull first or use--force-with-lease
carefully if you know you must overwrite the remote (only on personal branches, never on sharedmain
without coordination).Authentication: Set up SSH keys or token-based auth for your remotes to avoid repeated password prompts. GitHub/GitLab provide specific instructions for SSH setup.
🔍 Tips & Best Practices
🎯 Small, focused commits: Commit often with logical changes. Avoid “omnibus” commits that do many unrelated things. This makes review and reverts easier.
📝 Use meaningful branch names: e.g.
feature/login
,bugfix/typo
,hotfix/urgent-patch
. Some teams prefix with JIRA issue IDs. Keep them concise and descriptive.🖋 Maintain a good commit history: Use interactive rebase (
git rebase -i
) to squash or reorder messy local commits before sharing. A clean history helps everyone. If merging via pull requests, you might squash and merge to keepmain
linear.🔐 Protect important branches: Configure your remote (GitHub/GitLab) to require pull request reviews, pass CI checks, and disallow force pushes on
main
/master
and release branches. This prevents accidental overwrites.☑️ Review before pushing: Always
git status
andgit diff
to double-check what you’re about to commit or push. A quickgit log --oneline --decorate --graph
gives a visualization of where you stand.✅ Code reviews: As GitLab notes, “requesting feedback from others is an excellent way to ensure code quality”. Use pull request comments to discuss changes. Senior devs can mentor through reviews.
🔄 Rebase vs. Merge policy: Decide with your team when to rebase. A common rule is: rebase before merging (for your private branch) to keep history tidy, but never rebase a public branch (like one others are using). Merges on shared branches keep everyone’s copy in sync.
🛡️ Back up before big rewrites: If you are about to do something destructive (like
git filter-branch
, or a large rebase), make a backup of the repository folder (or a git bundle). It’s easy to lose work with powerful commands.🌐 Stay up-to-date with Git: New versions occasionally add helpful commands (
git switch
,git restore
in 2.23+,git worktree
to have multiple working directories from one repo, etc.). Check release notes or git-scm.com for new features.🤝 Communication: Always communicate with your team. If you must force-push a branch, alert others. If you encounter a tricky conflict, ask before just proceeding blindly. Good Git usage is as much about collaboration as it is about commands.
🌐 Cross-Platform & GUI Notes
Windows vs. macOS/Linux: Git commands are the same, but watch out for line endings (
core.autocrlf
). On Windows, path length can hit limits; Git for Windows provides Git Bash, a Unix-like terminal that smooths over many differences. On macOS/Linux, Git is native.-
GUI clients: They wrap Git in visual form. Here are a few notable ones:
- GitHub Desktop (Windows/macOS, free): Great for beginners, integrates GitHub features.
- Sourcetree (Windows/macOS, free): Visual branch management for Bitbucket/GitHub.
- GitKraken (cross-platform, free & paid tiers): Advanced UI, integrated issue tracking.
- Tower (macOS/Windows, paid): Feature-rich professional GUI.
- Many IDEs (VS Code, IntelliJ, etc.) have built-in or plugin Git integration, showing diffs and providing one-click commit/push. Choose one you like—just remember the underlying commands work the same way. Even with a GUI, know the CLI basics for troubleshooting.
🎉 Conclusion
Git is incredibly powerful and flexible. This guide has covered its core commands (init, clone, add, commit, status, log, diff, branch, checkout/switch, merge, pull, push), intermediate tools (rebase, stash, cherry-pick, tag, reset, revert, remote, submodule), and advanced techniques (bisect, reflog, blame, hooks). We’ve also touched on workflows, team collaboration tips, cross-platform considerations, and GUI alternatives.
Mastering Git takes practice. Always write clear commit messages, use branches to keep work isolated, and pull/merge frequently. Use code reviews to catch issues early. Back up your work with remotes and test merges on small changes first. And remember: if something goes wrong, commands like git reflog
, git reset
, and git revert
can often recover you.
By following the best practices above, Git will streamline your development and collaboration. Happy coding! 🚀
AquaScript APIs
This website is created by me and my Best Friends Precious Kelvin & Madhurima Rawat. AquaScript Offers free APIs to The Developers
Top comments (3)
Great writeup! Having commands like reflog and bisect spelled out here would've saved me hours in the past. What's the one 'advanced' Git command that's been a lifesaver for you?
Very detailed article. Nice one
Fantastic.