Git Tips¶
Resources¶
These resources are helpful for getting an understanding of how actually Git works, which generally makes it easier to use. I recommend checking them out.
Helpful Commands¶
The following are some helpful commands for working with Git locally. Please edit any descriptions you feel are unclear. And feel free to add your own go-to git commands to the list.
Better Rebases¶
git rebase --onto <branch> <base-commit>
The regular git rebase <branch> will automatically calculate a common ancestor commit and moves all subsequent commits over. This works fine if you're just rebasing on main for the latest changes git rebase main which should have a simple append-only commit history.
But issues can arise if you want to change the base of your branch from one to another, or get the latest changes from a base branch that was force pushed since you last pulled it. git rebase --onto solves this problem, and I default to it even for the simple case of rebasing off the latest main.
Case Study:
- I branch new and other off main separately, and commit on each.
- I realize other needs some of the changes from new.
- From other, I find the main commit I branched off (abc123def) and run git rebase --onto new abc123def.
- Git replays my other commits on top of new instead of main.
Regular git rebase could auto-resolve this case, but if new had been force pushed or rebased, it may not. git rebase --onto guarantees you end up with exactly the commits you expect.
Try this in the Learn Git Branching Sandbox for a visual demonstration of the above (in the sandbox the commit hash is shown in the node of each commit).
Selective Stashes¶
git stash push --staged
The standard git stash command is great. It saves all of your un-committed changes to be re-applied later with git stash pop. But what if you only want some of your changes to be saved?
git stash push --staged will only stash changes that are currently staged for commit. This effectively lets you choose any subset of your current changes with git add <file-name> to stash.
Selective Staging¶
git add -p <file-name>
This command takes you through the file in "hunks" (sections), allowing only certain portions to be staged. Type ? to see the various options for each hunk. Can be very useful for selective stashing above.
Search Git History¶
git log -S "Search"
git log -G "Search"
These commands allow you to search for files that added / removed the provided string. -S will show commits which changed the count of the string in the codebase, while -G will show any commit whose diff included the string (perhaps the line containing it was edited without the string itself changing).
Add --all to the end to search all branches, or -p to show the actual diff hunks containing the string. --source annotates each result with the ref it was reached through, which is useful with --all when you want to know which branch a commit lives on.
Recover Lost Work¶
git reflog
Every time HEAD moves — commits, checkouts, resets, rebases, merges — Git records the previous position in the reflog. Entries stick around for ~90 days by default. This means almost any "I just nuked my work" situation is recoverable as long as you haven't run git gc.
- git reflog to see the list of recent HEAD positions
- Find the entry from before things went wrong (e.g. HEAD@{4})
- git reset --hard HEAD@{4} to jump back, or git checkout HEAD@{4} to inspect first
Also works for commits made on a branch you've since deleted — the commits aren't gone, you just need the SHA from the reflog to get back to them (git checkout -b recovered <sha>).
Find the Commit That Broke Something¶
git bisect
Binary search through commits to find the commit that introduced a bug. You mark a known-bad commit and a known-good commit. Git checks out the midpoint and you tell it whether that revision is good or bad. It narrows the range each step until the bad commit is found.
git bisect start
git bisect bad # current HEAD is broken
git bisect good <older-sha> # this commit worked
# git checks out the midpoint — test it, then:
git bisect good # or: git bisect bad
# repeat until git prints the first bad commit
git bisect reset # return to your original HEAD
If you have a script or test that exits non-zero on the bug, git bisect run <cmd> automates the process.