Intermediate Git Commands for Developers

In this article, we will discuss some git commands that are going to make an individual more productive. For those who understand the basics of git and its command, then this article will definitely benifit. This guide covers the intermediate commands that makes developer and other stakeholders life easier.

For basics of git, you can look at this article, Essential Git Commands for Developers

git stash

Suppose, a poor guy is in the middle of adding a feature when his manager says "pause everything, there is a bug, fix it immediately". This guy's code is half-done, not ready to save, but also can't just delete it either. In such situation, he can use git statsh. It is like putting messy items from a table into a drawer, so one can deal with the emergency, then pull everything back out later.

We can stash multiple times and each stash stacks on top of the last.

git stash                       # Shove current changes into the drawer
git stash pop                   # Pull the most recent changes back out
git stash list                  # See everything in the drawer
git stash apply stash@{2}       # Pull out a specific item (without removing it)
git stash drop stash@{0}        # Permanently delete a specific stash

git rebase

When branches are merged, git creates extra "merge commits" that clutters git history. Rebase is an alternative, instead of merging, it takes the commits and replays them on top of another branch, so the history looks as if everything happened on a straight line.

git rebase main          # Replay your commits on top of main
git rebase -i HEAD~5     # Interactively rewrite the last 5 commits

The real power is interactive rebase, -i. It opens an editor where one can clean up his/her commits before sharing them.

  • pick: keep the commit as-is
  • squash: merge it into the previous commit
  • reword: change the commit message
  • drop: delete the commit entirely
  • edit: pause mid-rebase to make changes

Warning: Never rebase commits that have already been pushed to a shared branch. Rebase rewrites history, doing it on public commits will cause problem for other person working on this same project.


git cherry-pick

Sometimes we don't want to merge an entire branch, we just need that one specific commit. Cherry-pick lets us copy a single commit from one branch and apply it to another.

Example: A happy guy fixed a critical bug on main, but he also have a v2.0-release branch that needs the same fix, without pulling in all the half-finished features on main. Cherry-pick just that fix commit onto the release branch.

git cherry-pick <commit-hash>           # Pick one commit
git cherry-pick abc123 def456           # Pick multiple commits
git cherry-pick main~3                  # Pick using a relative reference

git bisect

Suppose, a developer got a situation where a bug exists today that didn't exist three weeks ago and she has no idea which commit introduced it. One solution is to check single commit one by one (not an optimal soultion). Other solution is to use git bisect, which nagivates commits using a binary search. It keeps cutting the commit range in half until it points the exact bad commit. For a repo with hundreds of commits, this command can save a lot of time.

git bisect start
git bisect bad                   # tells git that current code is broken
git bisect good 11ebc3c          # tells git that this commit was fine

# git automatically checks out a commit halfway between. 
# Test it & update the git using these commands
git bisect good    # if it works here
git bisect bad     # if it's broken here

# Keep going until git finds the culprit.
git bisect reset   # return to where we started

Note: git only does the navigation, it is the user who checks and say good or bad.


git reflog

git log shows us the project's history. git reflog shows history, every position the HEAD has ever been at, even after resets, rebases, and deletions. It can be useful when something is broken. Whenever a user accidentally ran git reset --hard and lost his/her work, he/she can find the commit hash in reflog and recover it.

git reflog               # See every recent HEAD movement
git reflog show main     # See the reflog for a specific branch

Warning: Reflogs are local to the machine and expire after 90 days by default.


git reset

git reset moves the branch pointer backwards to a previous commit. There are three modes, they all undo the commit, but differ in what happens to actual file changes.

git reset --soft HEAD~1    # Undo commit, keep changes staged (ready to re-commit)
git reset --mixed HEAD~1   # Undo commit, unstage changes (files still modified)
git reset --hard HEAD~1    # Undo commit, delete all changes permanently

git revert

git reset rewrites history, which is dangerous on shared branches. git revert is the safe alternative, instead of deleting a commit, it creates a new commit that undoes the changes. History doesn't change here.

Tips: When the branch has already been pushed and others are using it, always use revert over reset.

git revert <commit-hash>          # Undo a specific commit
git revert HEAD~2..HEAD           # Undo a range of commits
git revert --no-commit HEAD~3     # Stage the revert without committing yet

git log

Most people run git log and move on. But with a few flags it becomes a powerful tool for exploring your repo.

# Clean visual graph of all branches
git log --oneline --graph --decorate --all

# Show exactly what changed in each commit
git log -p

# Filter by author, time, or keyword
git log --author="RGT" --since="2 weeks ago" --grep="fix"

# See every commit that touched a specific file
git log --follow -- src/auth/login.js

# See how many commits each person has made
git shortlog -sn

We can also set up an alias and reuse it

git config --global alias.lg "log --oneline --graph --decorate --all"

git lg

git blame

git blame shows us, line by line, who last changed each line of a file and which commit. Don't get confused by the name, it is not about pointing fingers(blaming), it is about understanding why code was written the way it was.

git blame src/api/routes.js
git blame -L 40,60 src/api/routes.js    # Only look at lines 40–60

The best way to learn and get used to with these commands is to use them on a dummy repository where you can break things freely. Create a dummy repo, make a mess, and practice. Remember, practice makes a developer perfect.