DEV Community

Cover image for A Complete Guide to Git: Commands, Usage, and Step-by-Step Workflow
Bhadra Mohit
Bhadra Mohit

Posted on AI-assisted

A Complete Guide to Git: Commands, Usage, and Step-by-Step Workflow

Whether you're working solo on a side project or collaborating with a team of 50 developers, Git is the backbone of modern software development. It tracks every change you make, lets you experiment safely with branches, and makes collaboration possible without stepping on each other's code.

This guide walks through Git from the ground up — what it is, why you need it, and a detailed, hands-on breakdown of the commands you'll actually use every day, along with the ones you'll reach for once things get a little more advanced.


What is Git and Why Do You Need It?

Git is a distributed version control system (VCS) that tracks changes to files over time. "Distributed" means every developer has a full copy of the project's history on their own machine — not just the latest files, but every commit ever made. This is what makes Git fast, reliable, and usable even without an internet connection.

Git lets you:

  • Save "snapshots" of your project at any point (commits)
  • Go back to a previous version if something breaks
  • Work on new features without affecting the main codebase (branching)
  • Merge work from multiple people without overwriting each other's changes
  • Keep a full history of who changed what, and when, and why

Git vs a Traditional Save System

Aspect Without Git With Git
Change tracking Manual (copy-pasting folders like project_final_v2) Automatic, precise history of every change
Collaboration Risk of overwriting others' work Merge and conflict resolution built in
Rollback Difficult or impossible Instant — revert to any previous commit
Branching Not possible without duplicating folders Native, lightweight branching
Accountability No record of who changed what Full commit history with author and timestamp
Offline work Depends on manual backups Full history available locally, no network needed

Git vs GitHub — A Common Point of Confusion

Source: GitHub

It's worth clarifying this early: Git is the version control tool itself (installed on your machine). GitHub (along with GitLab, Bitbucket, etc.) is a cloud platform that hosts Git repositories and adds collaboration features like pull requests, issues, and code review. You can use Git without ever touching GitHub — but GitHub makes sharing and collaborating far easier.


Installing and Setting Up Git

Before using Git, install it for your OS (via git-scm.com, a package manager like apt/brew/choco), then configure your identity — this information gets attached to every commit you make.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Enter fullscreen mode Exit fullscreen mode

Some other useful one-time configuration steps:

git config --global init.defaultBranch main     # set default branch name to "main"
git config --global core.editor "code --wait"   # set VS Code as your commit message editor
git config --global color.ui auto               # enable colored output in the terminal
Enter fullscreen mode Exit fullscreen mode

Check your current configuration anytime:

git config --list          # view all settings
git config user.name       # view a specific setting
Enter fullscreen mode Exit fullscreen mode

Git config exists at three levels — --local (this repo only), --global (this user, all repos), and --system (all users on the machine). Local settings override global, which override system.


Starting a Project: init vs clone

There are two ways to start working with Git on a project.

git init — Start a New Repository

Turns your current folder into a Git repository, creating a hidden .git folder that stores all version history.

git init
git init my-project        # create the folder and initialize it in one step
Enter fullscreen mode Exit fullscreen mode

git clone — Copy an Existing Repository

Downloads a full copy of an existing repository (including all its history) from a remote source like GitHub.

git clone https://github.com/username/repository.git
git clone https://github.com/username/repository.git custom-folder-name
git clone --depth 1 https://github.com/username/repository.git   # shallow clone, history only from the latest commit
Enter fullscreen mode Exit fullscreen mode

init vs clone at a glance:

git init git clone
Creates a brand-new, empty repository Copies an existing repository
Used when starting a project from scratch Used when joining an existing project
No remote connection by default Automatically sets up the remote (origin)

The Core Git Workflow

Source: Medium

Understanding Git means understanding its three (or four) areas:

  1. Working Directory — Your actual project files, where you make edits
  2. Staging Area (Index) — A holding area for changes you're about to commit
  3. Local Repository (.git) — Where committed snapshots are permanently stored on your machine
  4. Remote Repository — The shared copy hosted on a server (e.g., GitHub), synced via push/pull

Here's the typical day-to-day flow, step by step:

Step 1: Check the Status

See what's changed, what's staged, and what's untracked.

git status              # detailed status
git status -s           # short, condensed format
Enter fullscreen mode Exit fullscreen mode

Step 2: Ignore Files You Don't Want Tracked

Before staging, it's worth setting up a .gitignore file so build artifacts, dependencies, and secrets never get committed by accident.

# .gitignore example
node_modules/
.env
*.log
dist/
.DS_Store
Enter fullscreen mode Exit fullscreen mode

Git will simply skip any file or folder pattern listed here when you run git add.

Step 3: Stage Your Changes

Move changes from the working directory into the staging area, preparing them for a commit.

git add filename.txt      # stage a specific file
git add folder/           # stage everything in a folder
git add .                 # stage all changed files in the current directory and below
git add -A                # stage all changes across the entire repo, including deletions
git add -p                # interactively choose which changes (hunks) to stage
Enter fullscreen mode Exit fullscreen mode

git add . vs git add -A:

git add . git add -A
Stages new and modified files in current directory and below Stages all changes across the entire repository
May miss deleted files outside current directory Includes deletions everywhere

Step 4: Commit Your Changes

Save a permanent snapshot of the staged changes, with a message describing what changed.

git commit -m "Add login functionality"
git commit -am "Fix navbar alignment bug"     # stage tracked files + commit in one step
git commit --amend -m "Corrected commit message"   # edit the most recent commit
git commit --amend --no-edit                  # add staged changes to the last commit without changing its message
Enter fullscreen mode Exit fullscreen mode

Tip: Only amend commits that haven't been pushed yet — amending shared history causes conflicts for collaborators.

Good commit messages matter. A widely used convention:

<type>: <short summary>

<optional longer description>
Enter fullscreen mode Exit fullscreen mode

Example: fix: correct off-by-one error in pagination logic

Common types: feat, fix, docs, style, refactor, test, chore.

Step 5: View History

git log                       # full commit history
git log --oneline             # condensed, one line per commit
git log --oneline --graph     # visual branch history
git log --author="Mohit"      # filter commits by author
git log -p filename.txt       # show changes made to a specific file over time
git show <commit-hash>        # show details and diff of one specific commit
git blame filename.txt        # see who last modified each line of a file
Enter fullscreen mode Exit fullscreen mode

Step 6: Push to a Remote Repository

Upload your local commits to a remote server like GitHub.

git push origin main
git push -u origin main        # push and set upstream tracking (only needed once per branch)
git push                       # after upstream is set, just this works
git push --force-with-lease    # safer force-push that fails if remote has new commits you don't have
Enter fullscreen mode Exit fullscreen mode

Caution: Avoid git push --force on shared branches — it overwrites remote history and can wipe out teammates' work. --force-with-lease is the safer alternative since it checks first.

Step 7: Fetch and Pull Updates

git fetch origin           # download remote changes WITHOUT merging them into your branch
git pull origin main       # fetch AND merge remote changes into your current branch
git pull --rebase          # fetch and rebase instead of merge, for a cleaner history
Enter fullscreen mode Exit fullscreen mode

fetch vs pull:

git fetch git pull
Downloads changes only Downloads AND merges changes
Safe — doesn't touch your working files Can create merge commits or conflicts immediately
Lets you review before merging Applies changes right away

Branching: Working on Features Independently

Branches let you work on new features or fixes without touching the main codebase until you're ready.

git branch                     # list all local branches
git branch -a                  # list all branches, including remote-tracking ones
git branch feature/login       # create a new branch
git checkout feature/login     # switch to that branch
git checkout -b feature/login  # create AND switch in one command
git switch feature/login       # modern alternative to checkout
git switch -c feature/login    # modern alternative to checkout -b
git branch -m old-name new-name   # rename a branch
Enter fullscreen mode Exit fullscreen mode

Merging Branches

Once your feature is ready, merge it back into the main branch.

git checkout main
git merge feature/login
git merge --no-ff feature/login   # always create a merge commit, even for fast-forward merges (preserves feature history)
Enter fullscreen mode Exit fullscreen mode

Resolving Merge Conflicts

Conflicts happen when the same lines of a file were changed differently on two branches. Git will pause the merge and mark the conflicting sections in the file:

<<<<<<< HEAD
your current branch's version
=======
the incoming branch's version
>>>>>>> feature/login
Enter fullscreen mode Exit fullscreen mode

To resolve it:

  1. Open the file and manually edit it to keep the correct content (removing the <<<<<<<, =======, >>>>>>> markers)
  2. Stage the resolved file — git add filename.txt
  3. Complete the merge — git commit (Git pre-fills a merge commit message for you)

If you want to back out of a conflicted merge entirely:

git merge --abort
Enter fullscreen mode Exit fullscreen mode

Deleting a Branch

git branch -d feature/login          # safe delete (only if merged)
git branch -D feature/login          # force delete (even if not merged)
git push origin --delete feature/login   # delete the branch on the remote too
Enter fullscreen mode Exit fullscreen mode

checkout/switch vs merge:

Command Purpose
git checkout / git switch Moves you between branches
git merge Combines changes from one branch into another

Undoing Changes: Choosing the Right Command

Git offers multiple ways to undo work, depending on how far you want to go back.

git restore — Undo Uncommitted Changes

git restore filename.txt          # discard changes in working directory
git restore --staged filename.txt # unstage a file (keep the edits)
git restore --source=HEAD~1 filename.txt   # restore a file to how it was one commit ago
Enter fullscreen mode Exit fullscreen mode

git reset — Move the Commit Pointer Backward

git reset --soft HEAD~1    # undo last commit, keep changes staged
git reset --mixed HEAD~1   # undo last commit, keep changes unstaged (this is the default mode)
git reset --hard HEAD~1    # undo last commit AND discard all changes permanently
git reset <commit-hash>    # reset to a specific commit
Enter fullscreen mode Exit fullscreen mode

git revert — Safely Undo a Commit (Recommended for Shared Branches)

Instead of erasing history, revert creates a new commit that undoes a previous one — safer for branches others are working on.

git revert <commit-hash>
git revert HEAD               # revert the most recent commit
git revert --no-commit <commit-hash>   # revert changes without auto-committing, so you can review first
Enter fullscreen mode Exit fullscreen mode

reset vs revert:

git reset git revert
Rewrites history (dangerous on shared branches) Preserves history, adds a new "undo" commit
Good for local, unpushed commits Good for commits already pushed/shared
Can permanently lose changes (--hard) Never loses commit history

git reflog — Your Safety Net

Even after a reset --hard, Git usually hasn't actually deleted your commits yet. reflog shows a log of everywhere HEAD has pointed, letting you recover "lost" commits.

git reflog
git checkout <commit-hash-from-reflog>
Enter fullscreen mode Exit fullscreen mode

Working with Remotes

git remote -v                                   # view connected remotes and their URLs
git remote add origin <repository-url>          # connect a remote repository
git remote remove origin                        # disconnect a remote
git remote rename origin upstream               # rename a remote
git remote show origin                          # detailed info about a remote, including tracked branches
Enter fullscreen mode Exit fullscreen mode

Stashing: Temporarily Saving Work

If you need to switch branches but aren't ready to commit, stash saves your uncommitted changes without a commit.

git stash                       # save current changes
git stash save "WIP: navbar fix"   # save with a descriptive message
git stash list                  # view all stashes
git stash pop                   # reapply the most recent stash and remove it from the list
git stash apply                 # reapply a stash but keep it in the list
git stash apply stash@{2}       # apply a specific stash by index
git stash drop stash@{0}        # delete a specific stash
git stash clear                 # delete all stashes
Enter fullscreen mode Exit fullscreen mode

Comparing Changes

git diff                     # changes in working directory not yet staged
git diff --staged            # changes staged but not yet committed
git diff branch1 branch2     # differences between two branches
git diff HEAD~2 HEAD         # differences between two commits
Enter fullscreen mode Exit fullscreen mode

Rewriting and Combining Commits

git rebase — Reapply Commits on Top of Another Branch

Rewrites commit history to create a cleaner, linear project history (compared to merge, which preserves branch structure).

git checkout feature/login
git rebase main
git rebase -i HEAD~3          # interactive rebase — reorder, edit, squash, or drop the last 3 commits
Enter fullscreen mode Exit fullscreen mode

During an interactive rebase, Git opens an editor listing your commits with options like pick, squash, reword, and drop next to each one — letting you clean up messy commit history before merging.

If conflicts occur during a rebase:

# fix the conflicted files, then:
git add .
git rebase --continue
# or to cancel entirely:
git rebase --abort
Enter fullscreen mode Exit fullscreen mode

merge vs rebase:

git merge git rebase
Preserves full branch history Creates a clean, linear history
Adds a merge commit No extra merge commit
Safe for shared/public branches Best used on local, unpushed branches

git cherry-pick — Apply a Specific Commit from Another Branch

Useful when you need just one specific fix from another branch, without merging everything.

git cherry-pick <commit-hash>
git cherry-pick <hash1> <hash2>     # cherry-pick multiple commits
Enter fullscreen mode Exit fullscreen mode

Tagging Releases

Tags mark specific points in history — commonly used for release versions (v1.0, v2.1.3).

git tag v1.0                        # create a lightweight tag
git tag -a v1.0 -m "Version 1.0"    # create an annotated tag with a message
git tag                             # list all tags
git push origin v1.0                # push a specific tag
git push origin --tags              # push all tags
git tag -d v1.0                     # delete a local tag
git push origin --delete v1.0       # delete a tag from the remote
Enter fullscreen mode Exit fullscreen mode

Bonus: Submodules and Aliases

Git Submodules

Submodules let you include one Git repository inside another — useful for shared libraries.

git submodule add https://github.com/user/library.git libs/library
git submodule update --init --recursive
Enter fullscreen mode Exit fullscreen mode

Git Aliases — Save Yourself Some Typing

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
git config --global alias.cm "commit -m"
Enter fullscreen mode Exit fullscreen mode

Now git st works exactly like git status.


Common Git Commands Cheat Sheet

Command Purpose
git init Initialize a new repository
git clone <url> Copy an existing repository
git status Show current state of working directory
git add . Stage all changes
git commit -m "message" Save a snapshot with a message
git push Upload commits to remote
git fetch Download remote changes without merging
git pull Download and merge remote changes
git branch List/create branches
git checkout / git switch Switch branches
git merge Combine branch changes
git log View commit history
git diff View unstaged/staged differences
git stash Temporarily save uncommitted changes
git reset Move commit pointer, optionally discarding changes
git revert Undo a commit safely with a new commit
git rebase Reapply commits for a linear history
git cherry-pick Apply a specific commit to the current branch
git tag Mark a specific commit (e.g., a release)
git reflog Recover lost commits or view HEAD history

A Realistic Step-by-Step Example

Here's what a typical feature development flow looks like end to end:

  1. Update your local main branchgit checkout main && git pull origin main
  2. Create a new branchgit checkout -b feature/user-profile
  3. Make your code changes in your editor
  4. Check what changedgit status
  5. Stage the changesgit add .
  6. Commit with a clear messagegit commit -m "feat: add user profile page"
  7. Push the branch to remotegit push -u origin feature/user-profile
  8. Open a Pull Request on GitHub/GitLab for review
  9. Address review feedback — make edits, then git add . and git commit --amend --no-edit or a new commit, then push again
  10. Resolve any merge conflicts if the main branch has moved forward
  11. Merge into main once approved, then delete the feature branch — both locally and on the remote

Wrapping Up

Git can feel overwhelming at first because of how many commands it has, but in practice, you'll use a small core set daily: status, add, commit, push, pull, branch, and merge. The rest — stash, rebase, cherry-pick, revert, reflog — become genuinely useful as your projects grow and your collaboration needs get more complex.

The best way to get comfortable with Git isn't memorizing every command — it's using it daily on real projects until the workflow becomes second nature. Break something, fix it, and you'll understand Git faster than any tutorial can teach you.


Made with care by Mohit Bhadra. If this guide helped you understand Git a little better, feel free to share it with someone who's still afraid of the command line.

Source: Github

Top comments (0)