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 "you@example.com"
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 --stagedshows staged but uncommitted changes. You can also dogit diff HEAD~1 HEADto 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.txtremoves (and stages removal of) a tracked file. - 
git mv old newrenames 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 branchlists 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 checkouthas 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
mainhasn’t moved since branching,git mergewill simply move themainpointer forward (fast-forward). For record-keeping, usegit merge --no-ff feature/loginto 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 fetchdownloads new commits and branches from the remote, but doesn’t merge them. - 
git pullis essentiallygit fetchplusgit 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 upstreamandgit 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 mergeintodevelopwhen done, and later release branches get merged intomain. Alternatively, feature-branch workflow means each feature gets its own branch and is merged intomainvia 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 stashtemporarily 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:- 
--softmoves the HEAD pointer to a previous commit but leaves all changes staged. - 
--mixed(default) unstages changes but keeps them in working dir. - 
--hardresets everything (HEAD, index, working dir) to the specified commit. Usegit resetwith 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 -fdeletes them from the working directory. Useful for cleaning build artifacts. (Add-dto remove untracked directories, and use-nto 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, ifmainhas 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-repoorgit filter-branch(rewrite history globally, e.g., remove a password from all commits). Each of these has powerful use-cases:- 
git bisectautomates a binary search through commit history to isolate the exact commit that introduced a bug. - 
git reflogshows all moves ofHEAD, enabling you to recover "lost" commits (for example, after an accidentalreset). - 
git blameannotates 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
maindirectly), feature-branch (one branch per feature, then PR merge), GitFlow (withdevelop/releasebranches) 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.autocrlfabove. Also, Unix permissions (executable bits) don’t always translate to Windows—use.gitattributesto 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/hooksor 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 addthe resolved files andgit commit(orgit rebase --continue). Usegit merge --abortto undo a merge in progress, orgit rebase --abortto 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 reflogto list whereHEADhas been. You can oftengit resetback to a commit hash shown inreflogto recover. Think ofreflogas undo history.git blame– Find origin of code. Rungit blame file.txtto 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 pushis rejected due to conflicts or non-fast-forward, pull first or use--force-with-leasecarefully if you know you must overwrite the remote (only on personal branches, never on sharedmainwithout 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 keepmainlinear.🔐 Protect important branches: Configure your remote (GitHub/GitLab) to require pull request reviews, pass CI checks, and disallow force pushes on
main/masterand release branches. This prevents accidental overwrites.☑️ Review before pushing: Always
git statusandgit diffto double-check what you’re about to commit or push. A quickgit log --oneline --decorate --graphgives 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 restorein 2.23+,git worktreeto 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 (6)
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.