PRACTICE TRACK / 49 QUESTIONS

Git
Think it through.

Branching, merging, rebasing, and recovery.

Choose a question, explain your approach, then reveal the supplied answer. Difficulty labels come from the existing question library.

49 questions

Answers stay closed until you choose to reveal them.

QUESTION 01GitHard

Explain git rebase -i (interactive rebase). Describe its primary use cases and walk through an example of squashing multiple commits into one, including the steps and commands involved.

#
Reveal answer guidance

git rebase -i <base-commit-hash> (or <branch-name>) allows you to rewrite commit history interactively. The <base-commit-hash> specifies the point in history where you want to start rewriting. Primary use cases include: (1) **Squashing commits**: Combining multiple small, WIP commits into a single, meaningful commit. (2) **Reordering commits**: Changing the order of commits. (3) **Editing commit messages**: Rewriting a commit message. (4) **Splitting commits**: Breaking a large commit into smaller ones. (5) **Deleting commits**: Removing unwanted commits. When you run git rebase -i, Git opens an editor with a list of commits and commands (pick, squash, edit, reword, drop, fixup). To squash multiple commits: 1. Identify the commits you want to squash. Let's say you have commit-A, commit-B, commit-C, and you want to squash B and C into A. 2. Run git rebase -i <commit-parent-of-A>. This opens an editor with commit-A, commit-B, commit-C listed. 3. Change the actions: pick <hash-A> commit-A; squash <hash-B> commit-B; fixup <hash-C> commit-C. squash combines the commit into the previous one and prompts for a new commit message. fixup combines and discards the commit's message. 4. Save and close the editor. Git will then apply the changes. If you chose squash, a new editor will open to combine commit messages. If conflicts arise, resolve them, git add ., and git rebase --continue. The result is a cleaner, linear history with fewer, more atomic commits.

QUESTION 02GitMedium

What are Git hooks, and how can they be used to enforce code quality or automate CI/CD tasks? Give examples of a pre-commit hook and a post-receive hook.

#
Reveal answer guidance

Git hooks are scripts that Git executes automatically before or after events like committing, pushing, or receiving pushed commits. They are categorized as client-side (run on the developer's machine) or server-side (run on the remote repository). They reside in the .git/hooks directory of a repository. To activate, remove the .sample extension from the example files or create new scripts. For **enforcing code quality**, a pre-commit hook (client-side) can run linters, formatters, or unit tests before a commit is finalized. Example (.git/hooks/pre-commit): #!/bin/bash; echo 'Running linting...'; pylint --rcfile=.pylintrc *.py || { echo 'Pylint failed! Aborting commit.'; exit 1; }. This script runs Pylint and aborts the commit if it fails. For **automating CI/CD tasks**, a post-receive hook (server-side) can trigger deployments or notifications after new code is pushed to the central repository. Example (.git/hooks/post-receive): #!/bin/bash; while read oldrev newrev refname; do if [[ "$refname" == "refs/heads/main" ]]; then echo 'Main branch updated, triggering deploy...'; curl -X POST https://ci.example.com/trigger?branch=main; fi; done. This hook checks if the main branch was updated and then triggers a CI/CD pipeline via a webhook. Hooks are powerful but can be bypassed (client-side) or require careful management (server-side) to ensure consistency across teams.

QUESTION 03GitMedium

How do you use git bisect to find the commit that introduced a bug? Walk through the steps, including how to handle non-binary outcomes (e.g., "skip").

#
Reveal answer guidance

git bisect uses a binary search algorithm to efficiently find the commit that introduced a bug within a range of commits. Steps: 1. **Start bisecting**: git bisect start. 2. **Mark a known bad commit**: git bisect bad <commit-with-bug> (usually HEAD). 3. **Mark a known good commit**: git bisect good <commit-before-bug-existed>. Git will then check out a commit roughly in the middle of the good and bad range. 4. **Test the current commit**: Run your tests. If the bug is present, run git bisect bad. If the bug is not present, run git bisect good. Git will again check out a new commit, narrowing the search range. 5. **Handle non-binary outcomes**: If a commit cannot be tested (e.g., it doesn't build, or the bug's environment isn't reproducible), use git bisect skip. Git will then pick another commit, ignoring the skipped one. 6. **Repeat**: Continue testing and marking commits as good/bad/skip until Git identifies the exact "first bad commit." 7. **End bisecting**: git bisect reset to return to your original HEAD state. For automation, you can use git bisect run <script> where <script> returns 0 for good, 125 for skip, and 1-127 (except 125) for bad. This automates the testing and marking process.

QUESTION 04GitHard

Compare and contrast Git submodules and Git subtrees. When would you choose one over the other, and what are their respective challenges?

#
Reveal answer guidance

Both Git submodules and subtrees allow embedding one Git repository inside another. **Git Submodules**: - **How it works**: Records a specific commit from an external repository. The submodule is effectively a separate repository at a fixed commit. - **Pros**: Clean separation of concerns; easy to track upstream changes by updating the submodule's recorded commit. - **Cons**: Can be complex to manage (requires explicit git submodule update), especially for new developers; repository cloning is a two-step process (git clone then git submodule update --init --recursive); can lead to a detached HEAD state in the submodule, making development within it tricky; upstream changes are pulled directly, not merged. - **Use cases**: Managing third-party libraries where you rarely contribute back, or when you need strict version control of dependencies. **Git Subtrees**: - **How it works**: Embeds the contents of an external repository directly into a subdirectory of your main repository. The external repo's history is merged into your main repo's history. - **Pros**: Simpler for new developers (no special clone/update steps); history of the subtree is part of the main repo's history; easier to make changes to the subtree and push them back upstream. - **Cons**: Larger repository size due to merged history; more complex to pull upstream changes (requires a merge operation); pushing changes back upstream requires a git subtree push command. - **Use cases**: Monorepos, when you frequently modify the shared component and push changes back, or when you want the embedded project's history to be part of your main project's history. **Choice**: Choose **submodules** for external dependencies you consume but rarely modify, or when you need strict, explicit version pinning. Choose **subtrees** for shared components you actively develop and contribute to, or when you want a simpler developer experience without the complexities of submodule management.

QUESTION 05GitHard

Beyond simple git reset, how can git reflog be used to recover seemingly "lost" commits, branches, or even entire repositories? Provide a scenario where git reflog is the only way to recover.

#
Reveal answer guidance

git reflog (reference log) is a powerful mechanism that records every time your HEAD (the pointer to your current commit) changes. This includes commits, resets, merges, rebases, checkouts, and even failed operations. Unlike git log, which shows only reachable commits, reflog tracks all local movements, making it the ultimate safety net for recovering "lost" work. Each entry in the reflog has an index (e.g., HEAD@{0}, HEAD@{1}) and the commit hash. **Scenario for recovery**: Imagine you're on main, create a new branch feature-A, make some commits, then accidentally delete the branch with git branch -D feature-A. You also ran git reset --hard HEAD~2 on main to remove some recent commits, thinking they were bad, and now you realize you need them back. At this point, git log won't show the deleted branch's commits or the reset commits. **Recovery steps**: 1. **View the reflog**: git reflog. This will show a history of your HEAD movements. You'll see entries like HEAD@{5}: reset: moving to HEAD~2 and HEAD@{10}: checkout: moving from feature-A to main. 2. **Identify the lost commit**: Look for the commit hash where your feature-A branch last pointed, or the commit hash of the work you reset --hard. For example, let's say HEAD@{10} was c1a2b3c (the last commit on feature-A) and HEAD@{5} was d4e5f6g (the commit before your reset --hard on main). 3. **Restore the branch/commits**: - To restore feature-A: git checkout -b feature-A c1a2b3c. - To restore main to its state before the reset --hard: git reset --hard d4e5f6g. reflog entries are typically retained for 90 days by default, after which they are garbage collected. It's crucial to understand that reflog is local to your repository; it does not exist on remote servers.

QUESTION 06GitEasy

What is the difference between git merge and git rebase?

#
Reveal answer guidance

merge creates a new merge commit that joins two histories, preserving exactly what happened (non-linear history). rebase replays your commits on top of another branch, producing a linear history but rewriting commit hashes. Use merge for shared/public branches; rebase to tidy up local work before pushing. Golden rule: never rebase commits you've already pushed and others have based work on.

QUESTION 07GitEasy

What is the difference between git fetch and git pull?

#
Reveal answer guidance

fetch downloads new commits/refs from the remote but doesn't change your working branch — you can inspect before integrating. pull is fetch + merge (or fetch + rebase with --rebase) into your current branch in one step. Fetch-then-review is safer when you want to see what changed first.

QUESTION 08GitMedium

How do you undo a commit that has already been pushed?

#
Reveal answer guidance

Use git revert <commit> — it creates a new commit that undoes the changes, keeping history intact and safe for shared branches. Avoid git reset + force-push on shared branches because it rewrites history others may have pulled. Reset/force is fine only on a private branch nobody else uses.

QUESTION 09GitMedium

What does git cherry-pick do and when would you use it?

#
Reveal answer guidance

cherry-pick applies the changes from a specific commit onto your current branch as a new commit. Useful for back-porting a single bug fix to a release branch, or pulling one commit out of a feature branch without merging the whole thing. Be mindful it duplicates the change, which can cause conflicts if that commit later gets merged too.

QUESTION 10GitHard

You committed to the wrong branch. How do you move the commits?

#
Reveal answer guidance

If unpushed: note the commits, switch to the correct branch (or create it), and either cherry-pick them over, or use git rebase --onto. Then on the wrong branch, git reset --hard origin/... (or to the commit before yours) to drop them. git reflog is your safety net to recover any commit you accidentally lose during the move.

QUESTION 11GitMedium

You accidentally committed a 500MB binary file three commits ago, then deleted it in the latest commit. The file is still in your repository history, bloating the clone size. How do you completely remove it from Git history on all branches without losing other commits?

#
Reveal answer guidance

Use git filter-branch or (preferred) git filter-repo (faster, maintained by Git community). With git-filter-repo: git filter-repo --path path/to/bigfile.bin --invert-paths. This rewrites history, removing the file from every commit. The file is gone from the entire history. Impact: (1) All commit hashes change (history rewrite). (2) Every collaborator must rebase their branches: git rebase --onto new-main old-main their-branch. (3) Force-push is required: git push origin --force-with-lease. (4) Notify all team members to re-clone or rebase. (5) After the rewrite, run git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(rest)' | awk '/^blob/ {print $NF}' | sort | uniq -c | sort -rn | head -20 to verify no large objects remain. (6) Run git gc --prune=now to clean up unreachable objects. Alternative: BFG Repo-Cleaner (bfg --delete-files bigfile.bin). For binary files in general, use git lfs to store them outside the repository proper.

QUESTION 12GitHard

During a complex merge conflict across 50 files involving 10 developers, describe your resolution strategy, communication plan, and verification process.

#
Reveal answer guidance

Strategy: (1) First, establish the merge base: git merge-base main feature-branch and review both sides of the diff: git log --oneline --left-right main...feature-branch. (2) Use a merge tool (vimdiff, Beyond Compare, git mergetool) for visual three-way merging. (3) Organize files by conflict type: auto-mergeable (deleted files, whitespace-only), simple conflicts (one side changed, one didn't), complex conflicts (both sides changed same region). Resolve simple conflicts first. (4) Communication: create a Slack/Discord channel, post the commit range, assign owners for each file domain (e.g., backend devs own API files, frontend devs own UI files). Use git checkout --ours/--theirs initially to create a working tree, then manually fix each conflicted area. (5) Verification: git diff --check for whitespace, git log --oneline --graph --left-right main...HEAD to see what's on each side. Run CI: tests, lint, build. (6) If merge is too complex, consider a "merge commit" strategy: merge main into the feature branch first (solving conflicts in private), then merge feature into main with --no-ff. (7) Post-merge: force-push the result to a review branch, have each domain owner verify their files, then finalize. Git's ort merge strategy (default since 2.33) handles renames and directory/file conflicts better than the old recursive strategy.

QUESTION 13GitHard

Explain Git's merge strategies: ort (default since 2.33), recursive, resolve, octopus, and ours. When would you explicitly choose recursive -X theirs vs -X ours, and what are the risks?

#
Reveal answer guidance

ort (Ostensibly Rec's Twin): new default, written in C for performance, handles renames+tweaks correctly, no index conflicts with git log. recursive: old default (Python-based via Git v2.33+ fallback), uses a recursive algorithm for criss-cross merge histories. resolve: simple 3-way merge, fast but cannot handle multiple merge bases — rare. octopus: merges more than 2 heads at once — used for topic branch merges but fails on conflicts. ours: keeps current branch content entirely, records merge but ignores incoming changes — used to mark a merge without actually taking changes (e.g., after reverting a feature). -X theirs auto-resolves conflicts by taking the incoming branch's version of conflicting hunks — useful for automated merges where you trust the incoming branch (e.g., cherry-pick backport). -X ours takes current branch's version. Risks: both -X theirs and -X ours silently discard the other side's changes in conflicted regions. This can introduce subtle bugs if a conflict represents a non-trivial integration point. Only use them when: (1) merging a hotfix back into main with known-safe conflicts (e.g., version number bumps); (2) during git rebase where you know your changes are correct and upstream conflicts are noise. Never use them without code review of the resulting diff.

QUESTION 14GitEasy

How do you initialize a new Git repository and connect it to a remote?

#
Reveal answer guidance

git init creates a new local repo. git remote add origin <url> links it to a remote. git push -u origin main sets the upstream and pushes. Most projects start with git clone <url> which does all three in one step.

QUESTION 15GitEasy

What does git status show that git log does not?

#
Reveal answer guidance

git status shows the working tree and index state: tracked/untracked files, staged changes, merge conflicts. git log shows commit history. They complement each other — use status to see what is about to be committed and log to see what was committed.

QUESTION 16GitEasy

What is the difference between git add ., git add -A, and git add -p?

#
Reveal answer guidance

git add . stages new and modified files in the current directory and below. git add -A stages all changes across the entire repo, including deleted files. git add -p (patch mode) interactively lets you stage individual hunks within a file.

QUESTION 17GitEasy

What is a gitignore file and why is it important?

#
Reveal answer guidance

A .gitignore file tells Git which files or patterns to ignore (not track). Common entries: build outputs (dist/, node_modules/), environment files (.env), OS files (.DS_Store), IDE configs (.idea/, .vscode/). Without it, generated files and secrets may accidentally be committed.

QUESTION 18GitEasy

How do you create and switch to a new branch in one command?

#
Reveal answer guidance

git checkout -b <branch-name> (classic) or git switch -c <branch-name> (modern, since Git 2.23). Both create the branch and switch to it immediately.

QUESTION 19GitMedium

What is a detached HEAD state and how do you recover?

#
Reveal answer guidance

Detached HEAD means you're checked out at a specific commit rather than a branch ref — any new commits won't be reachable from a branch. Recover by creating a branch at the current commit: git checkout -b new-branch-name. Common causes: git checkout <hash>, git checkout origin/main, or git rebase conflicts.

QUESTION 20GitMedium

How do you amend the most recent commit to fix a typo in the message or add a missing file?

#
Reveal answer guidance

For a message: git commit --amend -m "Fixed message". For a missing file: git add missing-file && git commit --amend --no-edit. Do NOT amend commits that have already been pushed to a shared branch — it rewrites history.

QUESTION 21GitMedium

What is a tracking branch and how do you set it up?

#
Reveal answer guidance

A tracking branch links a local branch to a remote branch so git push/git pull know where to sync without specifying the remote. Set it during push: git push -u origin <branch>. After that, plain git push and git pull work. git branch -vv shows tracking relationships.

QUESTION 22GitMedium

How does git stash work and when would you use it?

#
Reveal answer guidance

git stash temporarily shelves uncommitted changes, leaving a clean working tree. Useful when you need to switch branches mid-task. git stash pop restores the latest stash and removes it; git stash apply restores without removing. git stash list shows all stashes. git stash push -m "message" names them.

QUESTION 23GitMedium

How do you revert a merge commit that has already been pushed?

#
Reveal answer guidance

git revert -m 1 <merge-commit> tells Git which parent to keep (mainline) and creates a new commit undoing the merge. Unlike git reset, revert is safe on shared branches because it doesn't rewrite history. If you later need to re-merge, revert the revert commit.

QUESTION 24GitMedium

What is the difference between a fast-forward merge and a three-way merge?

#
Reveal answer guidance

Fast-forward: if the target branch hasn't diverged, Git simply moves the branch pointer forward — no merge commit. Three-way merge: when branches have diverged, Git creates a merge commit joining both histories. Use --no-ff to force a merge commit (useful for feature branches to preserve history).

QUESTION 25GitMedium

How do you rename a branch locally and on the remote?

#
Reveal answer guidance

Locally: git branch -m <old-name> <new-name>. Remote: push the new name and delete the old: git push origin -u <new-name> && git push origin --delete <old-name>. Update local clones of other developers: they fetch with git fetch --prune and switch to the new branch.

QUESTION 26GitMedium

How do you find which commit introduced a bug using git blame?

#
Reveal answer guidance

git blame <file> shows each line annotated with the commit hash, author, and timestamp of the last modification. Useful for finding 'who changed this line and when'. Combine with git log -p <commit> to see the full diff. git blame -L 10,20 <file> limits to a specific line range.

QUESTION 27GitMedium

How do you compare changes between two branches or commits?

#
Reveal answer guidance

git diff branch-a..branch-b shows changes on branch-b relative to branch-a. git log --oneline --left-right branch-a...branch-b shows which commits are unique to each side. git diff --stat summarizes file-level changes. For compare against the merge base: git diff branch-a...branch-b.

QUESTION 28GitMedium

What is git clean and when would you use it?

#
Reveal answer guidance

git clean removes untracked files from the working tree. git clean -n dry-runs (shows what would be deleted). git clean -f forces deletion of files. git clean -fd also removes untracked directories. git clean -fx removes files matched by .gitignore as well. Always dry-run first to avoid accidental loss.

QUESTION 29GitMedium

How do you apply the same commit to multiple branches?

#
Reveal answer guidance

Use git cherry-pick <commit-hash> — it applies the diff of a specific commit onto the current branch as a new commit. Common uses: backporting a bug fix to a release branch, or picking a single change from a feature branch without merging the whole thing. Watch for duplicate conflicts if the same commit is later merged.

QUESTION 30GitHard

How does Git's internal object model work (blobs, trees, commits, tags)?

#
Reveal answer guidance

Git is fundamentally a content-addressable filesystem. Four object types: (1) Blob — stores file content, identified by SHA-1 of its content. (2) Tree — maps filenames to blobs (or nested trees), like a directory listing. (3) Commit — points to a tree, has parent references, author, committer, and message. (4) Tag — points to a commit (lightweight) or to an object with metadata (annotated). All objects are stored in .git/objects/ as compressed files keyed by hash. git cat-file -p <hash> inspects any object.

QUESTION 31GitHard

How does Git handle large files and what is Git LFS?

#
Reveal answer guidance

Git stores every version of every file in the object store, which balloons with large binaries. Git LFS (Large File Storage) replaces large files with text pointers in Git and stores the actual content on a remote server (GitHub, GitLab). Files matching patterns in .gitattributes are auto-tracked by LFS. Benefits: clone times stay fast, diffs don't load the binary, storage is offloaded to the LFS server. LFS does have bandwidth quotas on most hosting platforms.

QUESTION 32GitHard

How do you completely remove a large file from Git history using git filter-repo?

#
Reveal answer guidance

git filter-repo --path large-file.bin --invert-paths rewrites every commit, stripping the file from all history. This changes every commit hash — a force-push is required. Afterward: git reflog expire --expire=now --all && git gc --prune=now --aggressive to reclaim storage. All collaborators must rebase onto the new history. For multiple repos, use --refs to target specific branches. git filter-repo is the maintained successor to git filter-branch, written in Python and much faster.

QUESTION 33GitHard

How does git bisect run automate binary search?

#
Reveal answer guidance

git bisect run <script> automatically executes the script at each bisect step. The script should exit 0 (good), 125 (skip — commit cannot be tested), or 1-127 (bad, except 125). Example: git bisect start HEAD v1.0 && git bisect run make test finds which commit broke the build. For flaky tests, return 125 to skip. The output shows the first bad commit hash and message.

QUESTION 34GitHard

What is a shallow clone and when would you use it in CI?

#
Reveal answer guidance

A shallow clone (git clone --depth 1) fetches only the latest commit without history. In CI it dramatically reduces clone time on large repos. Tradeoffs: you cannot git blame, git bisect, or git log beyond the depth. Use --depth N for the last N commits, --shallow-since=<date> for commits since a date, or --single-branch to limit to one branch. For monorepos, combine shallow clone with --sparse for checkout of specific directories only.

QUESTION 35GitHard

Explain Git's refspec format and how it controls push/fetch behavior.

#
Reveal answer guidance

A refspec maps remote refs to local refs in the format [+]<src>:<dst>. The optional + enables force-update. Default fetch refspec: +refs/heads/*:refs/remotes/origin/*. Default push: refs/heads/<branch>:refs/heads/<branch>. Custom refspecs let you fetch only specific branches (fetch = +refs/heads/main:refs/remotes/origin/main), push to a different remote branch name, or fetch pull requests (+refs/pull/*/head:refs/remotes/origin/pr/*).

QUESTION 36GitHard

How do you recover from a failed interactive rebase?

#
Reveal answer guidance

If you encounter conflicts during git rebase -i and panic: (1) git rebase --abort returns to the state before rebase started. (2) If you made partial progress and want to continue after fixing conflicts: git add . && git rebase --continue. (3) If you've already committed bad changes: use git reflog to find the commit before rebase started and git reset --hard HEAD@{N}. The reflog always has your back during rebase operations.

QUESTION 37GitHard

What is git worktree and how is it useful for multitasking?

#
Reveal answer guidance

git worktree add ../path branch-name checks out a branch in a separate directory while keeping your current worktree untouched. Benefits: (1) Work on two branches simultaneously without stashing or cloning twice. (2) Run tests on one branch while coding on another. (3) Review a PR in a dedicated directory. git worktree list shows all worktrees. git worktree prune cleans up after deleting a worktree's directory.

QUESTION 38GitHard

How does Git's commit-graph feature improve performance?

#
Reveal answer guidance

The commit-graph (git commit-graph write) stores commit metadata (parents, tree, generation number) in a binary file under .git/objects/info/commit-graph. This accelerates git log --graph, git merge-base, git rev-list, and reachability queries by avoiding decompression and parsing of individual commit objects. In large repos, operations can be 5-10x faster. Generation numbers enable topological ordering without walking the entire DAG. Git 2.18+ automatically writes commit-graphs during git gc.

QUESTION 39GitHard

How do you sign commits and tags with GPG/SSH, and why is this important in CI/CD?

#
Reveal answer guidance

Commits: git commit -S -m "message". Tags: git tag -s v1.0 -m "v1.0". Configure Git with user.signingkey and set git config commit.gpgsign true to sign automatically. CI/CD importance: verify signed commits on protected branches (git verify-commit HEAD), gate merges on signature verification, and prove provenance in supply chain security. GitHub displays a Verified badge for signed commits. SSH signing (Git 2.34+) is simpler than GPG for most teams.

QUESTION 40GitHard

How do you use git archive to export a clean copy of a repository?

#
Reveal answer guidance

git archive --format=zip --output=project.zip HEAD creates a ZIP or tar of the repository at the specified commit, without .git directory or untracked files. This is the correct way to distribute source code releases. git archive --format=tar --prefix=myproject/ v1.0 | gzip > myproject-v1.0.tar.gz creates a standard tarball. You can also archive a subdirectory: git archive HEAD:src/.

QUESTION 41GitHard

What is the difference between git log --all, git log --branches, and git log --remotes?

#
Reveal answer guidance

git log --all shows commits reachable from any ref (branches, tags, remotes). git log --branches shows only local branches. git log --remotes shows only remote-tracking branches. Use --graph --oneline --decorate with any to visualize the full commit topology. git log --branches --not --remotes finds commits on local branches not yet pushed.

QUESTION 42GitHard

How does Git's sparse checkout work and when would you use it in a monorepo?

#
Reveal answer guidance

Sparse checkout lets you check out only a subset of directories from a repository. Enable with git sparse-checkout init --cone, set patterns with git sparse-checkout set dir1/ dir2/, then clone with --sparse. In a monorepo with hundreds of projects, each CI pipeline only needs its own sources — sparse checkout reduces checkout time and disk usage. The cone mode (--cone) is much faster than the older non-cone mode.

QUESTION 43GitHard

What is the difference between git push --force and git push --force-with-lease?

#
Reveal answer guidance

--force blindly overwrites the remote ref, potentially destroying commits others have pushed. --force-with-lease checks that the remote ref is at the commit you expect before pushing — it protects against overwriting someone else's work. Always prefer --force-with-lease (or --force-if-includes) over --force. These are a safety net for force-push scenarios like rebased feature branches.

QUESTION 44GitMedium

How do you find commits that modified a specific line in a file?

#
Reveal answer guidance

git log -L <start>,<end>:<file> follows line history across renames. git blame <file> | grep <pattern> shows who last changed each matching line. git log -S <string> -- <file> (pickaxe) finds commits that added or removed a specific string. git log -G <regex> does the same with regex matching. These are essential for forensic debugging.

QUESTION 45GitMedium

What is the difference between HEAD^, HEAD~, HEAD~2, and HEAD@{2}?

#
Reveal answer guidance

HEAD^ = first parent of HEAD (same as HEAD~). HEAD~2 = grandparent (two commits back following first-parent). HEAD^2 = second parent of a merge commit. HEAD@{2} = where HEAD was 2 moves ago (from reflog — time-based, not ancestry-based). ~ traverses first-parent ancestry; ^ selects specific parent in merges.

QUESTION 46GitMedium

How do you set up a Git pre-commit hook to run linters automatically?

#
Reveal answer guidance

Create .git/hooks/pre-commit (executable). Example: #!/bin/sh; npm run lint || exit 1. To share hooks with the team, use pre-commit framework with .pre-commit-config.yaml or store scripts in .githooks/ and run git config core.hooksPath .githooks. The hook runs before each commit — if it exits non-zero, the commit is blocked.

QUESTION 47GitHard

How does Git's rerere (reuse recorded resolution) work?

#
Reveal answer guidance

git config rerere.enabled true records how you resolve merge conflicts and automatically reuses the same resolution the next time Git encounters the same conflict. The recorded resolutions are stored in .git/rr-cache/. Useful for long-lived feature branches that are repeatedly rebased onto main — the same conflicts appear each time, and rerere resolves them automatically. git rerere gc prunes stale cache entries. git rerere forget <path> clears a specific recorded resolution.

QUESTION 48GitHard

How do you use git replace to replace one commit with another?

#
Reveal answer guidance

git replace <object> <replacement> creates a ref in refs/replace/ that tells Git to substitute one object for another during operations like git log or git blame. Use cases: (1) replacing a commit message; (2) fixing a bad commit without rebasing; (3) grafting history (connecting two disjoint histories). The replacement is local — share with git push origin refs/replace/*. --graft creates a graft replacement to change parent pointers. git replace -l lists active replacements.

QUESTION 49GitHard

What is git fsck and how do you recover from a corrupted repository?

#
Reveal answer guidance

git fsck checks the object database for integrity and finds dangling objects (unreachable blobs/commits). Recovery: (1) git fsck --full identifies missing or corrupted objects. (2) If a commit is dangling, git cherry-pick <hash> or git branch recover <hash> saves it. (3) For missing objects, try git fetch --refetch or re-clone from a remote. (4) For packfile corruption, git unpack-objects < .git/objects/pack/*.pack then git gc to rebuild. (5) Worst case: reclone and cherry-pick any unpushed commits found in git fsck --lost-found.

CONTINUE PRACTICING

Try another perspective.