Documentation Index
Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
Use this file to discover all available pages before exploring further.
Git Advanced Topics
Take your Git skills to the next level with rebase, cherry-pick, stash, and understanding Git internals.Git Rebase
Rebase rewrites history by replaying your commits on top of another branch. Think of it like cutting your branch off the tree, moving to a higher point on the trunk, and reattaching it there. The commits look the same, but they now sit on a different foundation — and critically, they get new hashes.Rebase vs Merge
- Rebase: Clean linear history, feature branches that only you work on, cleaning up before a PR
- Merge: Preserving complete history, shared branches, when you want to know “when” branches diverged and joined
Interactive Rebase
pick- Use commit as-isreword- Change commit messageedit- Amend commitsquash- Combine with previous commitfixup- Like squash but discard messagedrop- Remove commit
Practical Example
Cherry-Pick
Cherry-pick lets you pluck a specific commit from one branch and apply it to another — like picking a single cherry from a tree without taking the whole branch. The original commit stays where it is; Git creates a new commit with the same changes but a different hash.- Hotfix to multiple branches: Fix a bug on main, cherry-pick it to release/v2.1
- Port feature to different version: Backport a feature from v3 to v2
- Recover specific changes: Pull one good commit from an otherwise broken branch
Git Stash
Stash is your “hold that thought” command. It temporarily shelves your uncommitted changes so you can switch context — handle an urgent bug, review a PR, or just try something else — and come back to exactly where you left off. Think of it like putting a bookmark in a book and lending it to someone; you pick it back up right where you stopped.Stash Options
Git Reflog
Reflog (reference log) records every movement of HEAD — every commit, checkout, rebase, reset, and merge. It is your ultimate safety net, the “undo history” that most people do not realize Git maintains. Even when a commit seems lost (after a bad rebase or accidental branch deletion), the reflog still has it for 90 days by default. Think of it as Git’s flight recorder — it logs where HEAD has been, even when the branches that pointed there are gone.- Undo bad rebase: Find the pre-rebase commit in reflog, reset to it
- Recover deleted branch: The commits still exist; find them in reflog and recreate the branch
- Find lost commits: After a hard reset or force push, reflog is your last resort
Git Bisect
Bisect performs a binary search through your commit history to find exactly which commit introduced a bug. Instead of manually checking 100 commits, bisect narrows it down in about 7 steps (log2(100)). It is like the number-guessing game: “Is the bug in this half or that half?”Automated Bisect
For the ultimate debugging workflow, give bisect a test script. It will run the script at each step and automatically mark commits as good or bad.Git Worktree
Worktrees let you check out multiple branches simultaneously in separate directories — without needing multiple clones. It is like having two desks side by side, each with a different project open. You can work on one, glance at the other, and neither interferes.- Review a PR while continuing work on your current feature
- Run two versions side by side for comparison testing
- Build a release branch while keeping your dev branch open
- Avoid constant stash/checkout/stash-pop cycles when context-switching frequently
Git Internals
Understanding how Git works under the hood transforms Git from a magic incantation into a predictable tool. At its core, Git is a content-addressable filesystem — a fancy way of saying “a key-value store where the key is a hash of the content.” Think of it like a library where books are shelved by fingerprint rather than by title. Change one sentence and the fingerprint changes, so it goes on a different shelf.Objects
Git stores everything as one of four object types:- Blob: Raw file contents (no filename, no permissions — just bytes). Two files with identical content share one blob.
- Tree: A directory listing — maps filenames and permissions to blobs (files) and other trees (subdirectories).
- Commit: A snapshot in time — points to a tree (the project state), parent commit(s), author, committer, and message.
- Tag: An annotated bookmark — points to a commit with a name, tagger info, and message. Lightweight tags are just refs.
References
Refs are human-readable pointers to commit hashes. Without them, you would have to remember 40-character SHA-1 strings. A branch is literally a 41-byte file containing a commit hash.The Index (Staging Area)
The index (.git/index) is a binary file that sits between your working directory and the repository. It tracks which file versions are staged for the next commit.
Advanced Workflows
Rebase Workflow
Fixup Commits
Git Hooks
Git hooks are scripts that fire automatically at specific points in the Git workflow — think of them as event listeners for your repository. If a hook exits with a non-zero code, the Git action is aborted. This makes them powerful quality gates that catch mistakes before they enter history.Git Aliases
Aliases let you create shortcuts for commands you type dozens of times per day. This is not just convenience — it removes friction that slows you down and makes complex commands discoverable by your team.Troubleshooting
Undo Last Commit (Keep Changes)
Undo Last Commit (Discard Changes)
Recover After Hard Reset
Fix Commit on Wrong Branch
Remove File from All History
Best Practices
Rebase Feature Branches
Rebase Feature Branches
git fetch origin && git rebase origin/main regularly. If the branch has been open for more than a day without rebasing, you are accumulating merge conflict risk.Never Rebase Public Branches
Never Rebase Public Branches
--force-with-lease) and error-prone. When in doubt, merge.Use Stash Liberally
Use Stash Liberally
git stash save "WIP: payment validation halfway done". Without messages, git stash list becomes a pile of mystery entries nobody dares touch.Learn Reflog
Learn Reflog
reset --hard, reflog still has the commits for 90 days. Run git reflog, find the hash you need, and git checkout -b recovery-branch <hash>. Practice this before you need it in a crisis.Prefer --force-with-lease Over --force
Prefer --force-with-lease Over --force
git push --force-with-lease instead of --force. It refuses to push if someone else has pushed to the branch since your last fetch — preventing you from silently overwriting a teammate’s work.Key Takeaways
- Rebase: Clean linear history, but never on public branches
- Cherry-pick: Apply specific commits across branches
- Stash: Temporary storage for uncommitted work
- Reflog: Safety net for recovering lost work
- Bisect: Binary search for bug-introducing commits
- Internals: Understanding objects makes Git less magical
Interview Deep-Dive
Your teammate force-pushed to a shared feature branch and overwrote your last three commits. Git log shows only their commits. How do you recover your work?
Your teammate force-pushed to a shared feature branch and overwrote your last three commits. Git log shows only their commits. How do you recover your work?
A production bug was reported but nobody knows when it was introduced. There have been 300 commits since the last known good release. Walk me through how you would use git bisect to find the offending commit.
A production bug was reported but nobody knows when it was introduced. There have been 300 commits since the last known good release. Walk me through how you would use git bisect to find the offending commit.
- I start by identifying a “good” commit (the last known working release tag, e.g.,
v2.3.0) and a “bad” commit (the current HEAD where the bug exists). Then I rungit bisect start,git bisect bad HEAD, andgit bisect good v2.3.0. - Git checks out the commit halfway between good and bad. I test whether the bug exists at this commit. If it does, I run
git bisect bad. If not,git bisect good. Each step halves the remaining commits. For 300 commits, this takes about 9 steps (log2(300) is roughly 8.2). - For maximum efficiency, I write a test script that can detect the bug automatically:
git bisect run ./test-regression.sh. The script exits 0 for “good” and non-zero for “bad.” Git runs it at each step automatically, finding the culprit in minutes without any manual intervention. - Once bisect identifies the first bad commit, I examine it with
git show <sha>. I then rungit bisect resetto return to my original branch. The identified commit usually makes the root cause obvious — it narrows the investigation from “somewhere in 300 commits” to “this specific 20-line diff.” - In practice, the hardest part is writing the automated test. If the bug requires a running database or external service, I might need to use a Docker-based test environment. If the bug is visual (UI regression), I might have to test manually at each step, but 9 manual tests is still far better than 300.
git bisect run will give incorrect results. I handle this by modifying the test script to run the test N times (e.g., 5) and report “bad” only if any run fails. The script exits with code 125 for “skip” if the commit cannot be tested (e.g., it does not compile). Code 125 tells bisect to skip that commit and try an adjacent one. For truly non-deterministic bugs, I increase the test repetitions at the cost of longer bisect time — 5 runs x 9 steps is still only 45 test executions, which is manageable.Explain the Git reflog to me as if I have never heard of it. Then tell me a real scenario where it saved someone's day.
Explain the Git reflog to me as if I have never heard of it. Then tell me a real scenario where it saved someone's day.
- Think of the reflog as Git’s flight recorder. Every time HEAD moves — every commit, checkout, rebase, merge, reset, pull, cherry-pick — Git records the before-and-after in the reflog. It is a chronological log of “where was HEAD 5 minutes ago, 1 hour ago, yesterday.” Even if you delete a branch, reset to an earlier commit, or mess up a rebase, the reflog remembers the commit SHAs from before the operation.
- The reflog is local to your machine. It is not pushed or shared. By default, entries expire after 90 days for reachable commits and 30 days for unreachable ones.
- Real scenario: a developer was rebasing a 2-week-old feature branch onto main and hit a cascade of merge conflicts. They panicked, tried to abort but accidentally ran
git reset --hardto a wrong commit. Their branch now pointed to a commit from 2 weeks ago, and their last 2 weeks of work was not on any branch. - Recovery:
git reflogshowed the exact commit SHA from before the rebase started (the entry read something likeHEAD@{7}: checkout: moving from main to feature-x). They rangit branch recovery HEAD@{7}, confirmed the recovery branch had all their work, and deleted the mangled feature branch. Total recovery time: under 2 minutes. - The lesson:
git reflogis why I tell junior developers “in Git, nothing is truly lost for 90 days.” The only operations that can cause permanent data loss aregit reflog expire(which nobody should run) andgit gc --prune=now(which aggressively garbage-collects unreachable objects).
git branch keep-this abc123. As long as a ref points to a commit, git gc will never remove it. For systemic protection, you can increase the reflog expiry time: git config gc.reflogExpireUnreachable 180 extends the window from 30 to 180 days for unreachable commits. But the best practice is to always create a branch for any commit you want to preserve — refs are cheap and explicit.Congratulations! You’ve completed the Git Crash Course. You now have the skills to use Git professionally, from basics to advanced workflows. Next: Linux Crash Course →