Advanced File-Level Operations
1. Granular Staging & Discarding
-
Interactive Patch Mode (
-p)To interactively stage or discard specific blocks of changes (hunks), you can use the following commands:
-
git add -p <file> -
git restore -p <file>
During this process, several options are provided:
-
y(yes, apply) -
n(no, skip) -
q(quit completely) -
a(apply this and all remaining) -
d(skip this and all remaining) -
e(manually edit the hunk).
-
-
Manually Editing Hunks (
e)Selecting
eopens the raw patch in a text editor. Git determines actions based on the first character of each line:-
+(addition) -
-(deletion) -
a space (unchanged context).
The way you manually edit is as follows:
-
To prevent staging an addition, completely delete the
+line from the patch. -
To prevent staging a deletion, replace the
-with a single space to turn it into a context line. -
Context lines must remain intact for the patch to apply cleanly.
-
2. git diff
-
git diff: Worktree vs. Index -
git diff --staged: Index vs. HEAD -
git diff <commit>: Worktree vs. Specific Commit -
git diff --staged <commit>: Index vs. Specific Commit -
git diff <commit_1> <commit_2>: Commit vs. Commit
3. git show
-
git show optional_commit: Show changes made during the commit specified -
git show optional_commit:file_name: peek at an old file in that commit -
git show optional_commit -- file_name: see changes to a file during that commit
4. Surgical History Inspection
-
File-Level and Line-Level Tracing
git log -p -- <file>shows the full diff history of a file, whilegit blame <file>shows who last modified each surviving line.To trace the complete evolutionary history of a specific line or block of code, use
git log -L <start>,<end>:<file>. This outputs every commit and patch that ever touched those exact coordinates. -
Syntax Differences (
log -Lvs.blame -L)git log -Lrequires a colon between the line range and the file name (e.g.,-L 10,20:main.c) becauselogcan accept multiple file paths, so the colon binds the range to a specific file.git blame -Luses a space (e.g.,-L 10,20 main.c) becauseblameonly ever operates on a single file, making the file name a standard positional argument.
5. Reading Unified Diff Formats
-
Anatomy of a Patch
When viewing raw patches (like from
log -L), the output is structured into specific metadata blocks.It includes the Commit Metadata (Hash, Author, Date, Message), the Diff Header (
a/for the old file state,b/for the new file state), the Hunk Header coordinates (e.g.,@@ -3,1 +3,1 @@showing the start line and number of lines extracted for both states), and the Payload (the actual+and-code changes).
6. Revision Ranges and History Traversal
-
Navigating Ancestry (
~and^)You can navigate backward through commit history using
HEAD~1(parent),HEAD~2(grandparent), etc.Attempting to reference an ancestor that does not exist (such as calling
HEAD~2when the repository only has two commits) results in afatal: bad revisionerror because the root commit has no parent. -
Mathematical Set Difference (
..)The
A..Bsyntax in Git does not represent a simple chronological range. It is a set difference operator meaning: "Commits reachable by B, excluding commits reachable by A."For example,
HEAD~1..HEADsubtracts the entire history of the parent commit from the current commit's history, resulting in exactly one commit: the delta between the two. -
The Path Separator (
--)When executing commands where a revision or branch name could be confused with a file name, appending
--before the file path explicitly forces Git's parser to treat all subsequent arguments as files, preventing ambiguous argument errors.
7. Daily Idioms (Quick Reference)
-
Review, stage, and commit a file in one seamless command:
git commit -p <file> -
Search the history of a file for exactly when a specific string or function was added or deleted (The Pickaxe):
git log -S "string_to_search" -- <file> -
See exactly what changes were introduced by the very last commit for a specific file:
git show HEAD -- <file> -
Trace the history of a specific C/C++ function by name (instead of line numbers):
git log -L :function_name:main.cThis uses Git's syntax heuristics to automatically locate the start and end boundaries of the function, outputting every patch in history that ever modified its internal logic.
-
Review the precise code changes made to a file in the last 3 commits (you can specify the commit to traverse backward from):
git log commit_name(opt) -3 -p -- <file>The
-3limits the output length, while the-pforces Git to render the actual unified diffs rather than just the commit metadata and messages. -
Audit all modifications made to a file since branching off from an older commit (exclusive):
git log older_commit..HEAD -p -- <file>This applies the set difference operator to isolate and display every change introduced to the file after the
older_commit, up to your current working state. -
Investigate how a specific block of code evolved between two precise points in time:
git log older_commit..newer_commit -L 10,20:main.cThis combines the mathematical set difference operator with surgical line tracing, rendering the evolution of lines 10 through 20 strictly bounded within that specific era of the repository's history.