The Git commands most developers avoid — interactive rebase, bisect, reflog, worktrees — are exactly the ones that save hours when you understand them. They are not dangerous when used correctly, and the mental model behind each one is simpler than it looks.
Why Intermediate Developers Plateau With Git
Most developers learn git add, git commit, git push, git pull, and git merge. That gets you through 90% of daily work. The remaining 10% — cleaning up a messy branch before a PR, finding which commit broke something, recovering from an accidental reset — is where developers either panic or spend unnecessary hours.
These are not advanced features. They are core tools that happen to sound intimidating.
Interactive Rebase: Cleaning Up History Before It Matters
Interactive rebase (git rebase -i) lets you rewrite commits on a branch before merging. You can squash multiple commits into one, reorder commits, edit commit messages, or split a commit into smaller ones.
The most common use case: you made 8 commits while working on a feature — "WIP", "fix typo", "actually fix it", "add tests", "fix tests", "remove debug log", "final cleanup", "really final". Interactive rebase turns this into 2 clean commits: "Add feature X" and "Add tests for feature X".
git rebase -i HEAD~8
This opens your editor with the last 8 commits listed. Change pick to squash (or s) for commits you want to merge into the previous one. Change pick to reword (or r) to edit a commit message. Save and close the editor, then write the new combined commit message.
The rule: only rebase commits that have not been pushed to a shared branch. If others have pulled your commits, rewriting history causes problems. On your own feature branch that only you are working on, interactive rebase is always safe.
Cherry-Pick: Applying One Commit to Another Branch
git cherry-pick <commit-hash> applies a specific commit to your current branch without merging everything else from the source branch.
When you need it: a bug fix was committed to main and you need it in your release branch. A feature was developed on one branch and part of it needs to land in a hotfix branch immediately. A teammate committed something useful to their feature branch that you need right now.
git cherry-pick abc1234
Cherry-pick creates a new commit on your current branch with the same changes as the specified commit. The commit hash is different, but the diff is identical.
You can cherry-pick a range of commits:
git cherry-pick abc1234..def5678
If conflicts arise, resolve them like you would a merge conflict, then run git cherry-pick --continue.
Bisect: Binary Search for the Bug-Introducing Commit
git bisect is one of the most underused Git commands. It uses binary search to find exactly which commit introduced a bug. Instead of reading through 50 commits guessing where things went wrong, bisect cuts the search space in half with each step.
git bisect start
git bisect bad # current commit has the bug
git bisect good v1.2.0 # this tag/commit did not have the bug
Git checks out a commit halfway between good and bad. You test whether the bug exists, then tell Git:
git bisect good # this commit is fine
# or
git bisect bad # this commit has the bug
Git halves the remaining range again. After 6-7 steps for a range of 50 commits, bisect identifies the exact commit. Run git bisect reset to return to your original position.
You can automate bisect with a script that exits 0 for good and 1 for bad:
git bisect run npm test
This runs the test suite at each step automatically. For a large codebase with a reliable failing test, bisect can find the culprit commit in under a minute with zero manual steps.
Reflog: Recovering "Lost" Commits and Branches
git reflog shows a log of everywhere HEAD has pointed in the last 90 days. Every commit, checkout, reset, and rebase is recorded here.
When you accidentally run git reset --hard and lose commits, or delete a branch you needed, reflog is how you recover.
git reflog
Find the commit hash from before your mistake, then:
git checkout -b recovery-branch abc1234
This creates a new branch at the "lost" commit. Nothing is actually gone unless you run git gc and the commits are older than the reflog expiry (90 days by default).
Reflog is local — it is not pushed to remote. If you clone a repository fresh, the reflog is empty. But for your local working copy, it is an almost-always-there safety net.
Worktrees: Two Branches at Once Without Stashing
git worktree lets you check out a second branch into a separate directory while keeping your current branch intact. No stashing, no switching back and forth.
git worktree add ../project-hotfix hotfix/critical-bug
This creates a new directory at ../project-hotfix with the hotfix/critical-bug branch checked out. Your main project directory stays on whatever branch it was on. Both directories share the same Git repository — commits made in either place are visible in both.
When you are done with the worktree:
git worktree remove ../project-hotfix
When worktrees are useful: you are deep in a feature branch and a critical bug needs fixing immediately. You want to run the test suite on main while working on a feature. You are reviewing a colleague's PR and want to run it alongside your own work.
Named Stashes: Better Than Numbered Stashes
git stash with no name creates stash@{0}, stash@{1}, etc. With many stashes, these are hard to identify.
git stash push -m "WIP: payment form validation"
List named stashes with git stash list. Apply a specific one with git stash apply stash@{0}. Drop a specific one with git stash drop stash@{0}.
Signing Commits with GPG
Signed commits prove that a commit actually came from you — not from someone who gained access to your account or pushed directly to a repository. GitHub shows a "Verified" badge on signed commits.
Setup is a one-time process: generate a GPG key, add the public key to GitHub, configure Git to sign automatically:
git config --global commit.gpgsign true
git config --global user.signingkey YOUR_KEY_ID
Signing is increasingly expected on projects with serious security requirements.
The 5 Git Aliases Every Developer Should Have
Add these to your ~/.gitconfig:
[alias]
lg = log --oneline --graph --decorate --all
st = status -s
co = checkout
br = branch
undo = reset HEAD~1 --mixed
git lg shows a visual branch graph in the terminal. git undo undoes the last commit while keeping the changes staged. These are not fancy — they remove friction from the commands you run dozens of times a day.
Keep Reading
- Lazygit Git Workflow Guide — a terminal UI for Git that makes these operations visual and less intimidating
- CI/CD for Small Engineering Teams — how Git branch strategies affect your deployment pipeline
- GitHub Actions Guide for Developers — automating the workflow that starts with your Git commits
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace — chat, projects, time tracking, AI meeting summaries, and invoicing — in one tool. Try it free.