git-staging
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNon-interactive Git Staging
非交互式 Git 暂存
When to use this skill
什么时候使用本技巧
Use this skill when you need to:
- Stage only specific hunks from a file (not the entire file)
- Stage only specific lines within a hunk
- Avoid interactive git commands (,
git add -p, etc.)git add -i - Programmatically control exactly what gets staged
当你需要完成以下操作时使用本技巧:
- 仅暂存文件中的特定 hunk(而非整个文件)
- 仅暂存某个 hunk 内的特定行
- 避免使用交互式 Git 命令(、
git add -p等)git add -i - 通过编程方式精准控制要暂存的内容
Step 1: Assess the changes
步骤 1:评估变更
Before choosing a staging method, determine what changes exist:
bash
git status # See which files have changes
git diff --no-ext-diff # See all unstaged changes
git diff --cached --no-ext-diff # See already-staged changesDecision tree:
- If only ONE file has changes and you want ALL of them staged → use
git add <file> - If ONE file has multiple unrelated hunks and you want only SOME → use Method 2 or 3
- If MULTIPLE files need staging → stage per-file with for each, or selectively with patch method
git add
选择暂存方法前,先确认存在哪些变更:
bash
git status # 查看哪些文件有改动
git diff --no-ext-diff # 查看所有未暂存的变更
git diff --cached --no-ext-diff # 查看已暂存的变更决策树:
- 如果只有 1 个文件有变更且你需要暂存它的所有改动 → 使用
git add <file> - 如果 1 个文件有多个不相关的 hunk 且你只需要暂存部分 → 使用方法 2 或 3
- 如果有多个文件需要暂存 → 对每个文件单独执行 暂存,或使用补丁方法选择性暂存
git add
Why not use git add -p
?
git add -p为什么不使用 git add -p
?
git add -pInteractive git commands require a TTY and human input. AI agents cannot
reliably fake interactive sessions - attempts using or are
fragile and often fail. Instead, construct patches programmatically and apply
them directly to the index.
echo "y"yes交互式 Git 命令需要 TTY 和人工输入。AI Agent 无法可靠地模拟交互式会话——使用 或 的尝试稳定性差,经常失败。更好的做法是通过编程方式构造补丁,直接将其应用到索引(index)。
echo "y"yesCore technique
核心技术
The key insight is that applies a patch directly to the
staging area (index) without modifying the working tree. This lets you stage
precise changes non-interactively.
git apply --cached核心思路是 可以直接将补丁应用到暂存区(index),无需修改工作树。这让你可以非交互式地暂存精确的变更。
git apply --cachedTemporary files
临时文件
All temporary patch files should be written to within the repository
(not ) to avoid permission prompts. Ensure the directory exists first:
tmp//tmpbash
mkdir -p tmp所有临时补丁文件都应该写入代码仓库内的 目录(而非系统的 ),避免权限提示。首先确保该目录存在:
tmp//tmpbash
mkdir -p tmpMethods
方法
Method 1: Stage entire file
方法 1:暂存整个文件
When you want to stage all changes in a file:
bash
git add <file>当你需要暂存某个文件的所有变更时:
bash
git add <file>Method 2: Stage specific hunks via patch
方法 2:通过补丁暂存特定 hunk
When you need to stage only certain hunks from a file:
-
Generate the full diff for the file:bash
git diff <file> > tmp/full.patch -
Edit the patch to keep only the hunks you want to stage (use the Edit tool or create a new file with only the desired hunks)
-
Apply the edited patch to the index:bash
git apply --cached tmp/selected.patch
当你只需要暂存文件中的部分 hunk 时:
-
生成该文件的完整 diff:bash
git diff <file> > tmp/full.patch -
编辑补丁,仅保留你想要暂存的 hunk(使用编辑工具,或创建仅包含目标 hunk 的新文件)
-
将编辑后的补丁应用到索引:bash
git apply --cached tmp/selected.patch
Method 3: Stage specific lines within a hunk
方法 3:暂存 hunk 内的特定行
When you need to stage only certain lines within a hunk, you must carefully
edit the patch to maintain validity:
-
Generate the diff:bash
git diff <file> > tmp/full.patch -
Edit the patch, following these rules for the hunk you're modifying:
- Keep the hunk header but adjust the line counts
@@ - To exclude an added line (): remove the entire line from the patch
+ - To exclude a removed line (): change
-to a space (-) to make it context - Adjust the line counts in the header to match
@@ -X,Y +X,Z @@
- Keep the
-
Apply:bash
git apply --cached tmp/selected.patch
当你需要暂存某个 hunk 内的特定行时,必须仔细编辑补丁以保证其有效性:
-
生成 diff:bash
git diff <file> > tmp/full.patch -
编辑补丁,对于你要修改的 hunk 遵循以下规则:
- 保留 hunk 头,但调整行数计数
@@ - 要排除某条新增行(开头):从补丁中删除整行
+ - 要排除某条删除行(开头):将
-改为空格(-),使其成为上下文行 - 调整 头中的行数计数,使其匹配实际内容
@@ -X,Y +X,Z @@
- 保留
-
应用:bash
git apply --cached tmp/selected.patch
Patch format reference
补丁格式参考
A unified diff patch has this structure:
diff
diff --git a/file.txt b/file.txt
index abc123..def456 100644
--- a/file.txt
+++ b/file.txt
@@ -10,6 +10,8 @@ optional context label
context line (unchanged)
-removed line
+added line
context line (unchanged)统一 diff 补丁的结构如下:
diff
diff --git a/file.txt b/file.txt
index abc123..def456 100644
--- a/file.txt
+++ b/file.txt
@@ -10,6 +10,8 @@ optional context label
context line (unchanged)
-removed line
+added line
context line (unchanged)Hunk header format
Hunk 头格式
@@ -START,COUNT +START,COUNT @@- First pair: original file (lines being removed or used as context)
- Second pair: new file (lines being added or used as context)
- COUNT = number of lines in that side of the hunk (context + changes)
@@ -START,COUNT +START,COUNT @@- 第一组:原始文件(被删除或用作上下文的行)
- 第二组:新文件(被新增或用作上下文的行)
- COUNT = hunk 对应侧的行数(上下文 + 变更)
Line prefixes
行前缀
- (space): context line (unchanged, appears in both versions)
- : line only in original (will be removed)
- - : line only in new version (will be added)
+
- (空格):上下文行(无改动,两个版本都存在)
- :仅存在于原始版本的行(会被删除)
- - :仅存在于新版本的行(会被新增)
+
Example: Staging only the second hunk
示例:仅暂存第二个 hunk
Given a file with two hunks of changes:
bash
undefined假设某个文件有两个 hunk 的变更:
bash
undefinedGenerate full diff
生成完整 diff
git diff --no-ext-diff myfile.py > tmp/full.patch
The patch might look like:
```diff
diff --git a/myfile.py b/myfile.py
index abc123..def456 100644
--- a/myfile.py
+++ b/myfile.py
@@ -5,6 +5,7 @@ import os
def foo():
pass
+ # Added comment in first hunk
def bar():
@@ -20,6 +21,7 @@ def bar():
def baz():
pass
+ # Added comment in second hunkTo stage only the second hunk, create a new patch with just that hunk:
diff
diff --git a/myfile.py b/myfile.py
index abc123..def456 100644
--- a/myfile.py
+++ b/myfile.py
@@ -20,6 +21,7 @@ def bar():
def baz():
pass
+ # Added comment in second hunkThen apply:
bash
git apply --cached tmp/second-hunk.patchgit diff --no-ext-diff myfile.py > tmp/full.patch
补丁内容可能如下:
```diff
diff --git a/myfile.py b/myfile.py
index abc123..def456 100644
--- a/myfile.py
+++ b/myfile.py
@@ -5,6 +5,7 @@ import os
def foo():
pass
+ # Added comment in first hunk
def bar():
@@ -20,6 +21,7 @@ def bar():
def baz():
pass
+ # Added comment in second hunk要仅暂存第二个 hunk,创建仅包含该 hunk 的新补丁:
diff
diff --git a/myfile.py b/myfile.py
index abc123..def456 100644
--- a/myfile.py
+++ b/myfile.py
@@ -20,6 +21,7 @@ def bar():
def baz():
pass
+ # Added comment in second hunk然后应用:
bash
git apply --cached tmp/second-hunk.patchExample: Excluding specific added lines
示例:排除特定新增行
If you have a hunk with multiple additions but only want to stage some:
Original hunk:
diff
@@ -10,4 +10,7 @@
existing line
+line I want to stage
+line I do NOT want to stage
+another line I want to stage
more contextEdit to exclude the unwanted line (remove it entirely and adjust count):
diff
@@ -10,4 +10,6 @@
existing line
+line I want to stage
+another line I want to stage
more contextNote: The became because we removed one added line.
+10,7+10,6如果你有一个包含多条新增内容的 hunk,但只想暂存其中一部分:
原始 hunk:
diff
@@ -10,4 +10,7 @@
existing line
+line I want to stage
+line I do NOT want to stage
+another line I want to stage
more context编辑补丁排除不需要的行(整行删除并调整计数):
diff
@@ -10,4 +10,6 @@
existing line
+line I want to stage
+another line I want to stage
more context注意: 变成了 ,因为我们删除了一条新增行。
+10,7+10,6Verification
验证
After applying, verify what was staged:
bash
git diff --cached # Show staged changes
git diff # Show unstaged changes (should include excluded hunks)
git status # Overview of staged/unstaged state应用补丁后,验证暂存的内容:
bash
git diff --cached # 查看已暂存的变更
git diff # 查看未暂存的变更(应该包含被排除的hunk)
git status # 暂存/未暂存状态概览Common pitfalls
常见陷阱
-
Invalid line counts: If theheader counts don't match the actual lines in the hunk,
@@will fail. Always recount after editing.git apply -
Missing newline at EOF: Patches are sensitive to trailing newlines. Watch formarkers.
\ No newline at end of file -
Whitespace corruption: Ensure context lines start with a space, not an empty prefix. Some editors strip trailing spaces.
-
Index mismatch: Theline is optional for
index abc123..def456. If you have issues, try removing it.git apply --cached
-
行数计数无效:如果头中的计数和 hunk 内的实际行数不匹配,
@@会失败。编辑后务必重新计数。git apply -
文件末尾缺少换行符:补丁对末尾换行符非常敏感。留意标记。
\ No newline at end of file -
空白符损坏:确保上下文行以空格开头,而非空前缀。部分编辑器会删除行尾空格。
-
索引不匹配:不需要
git apply --cached行。如果你遇到问题,可以尝试删除该行。index abc123..def456
Troubleshooting
故障排查
If fails:
git apply --cached-
Test the patch first without:
--cachedbashgit apply --check tmp/selected.patch -
Use verbose mode to see what's happening:bash
git apply --cached -v tmp/selected.patch -
Common error messages:
- "patch does not apply": Line counts are wrong or context doesn't match
- "patch fragment without header": Missing the or
diff --gitlines---/+++
如果 失败:
git apply --cached-
先不带参数测试补丁:
--cachedbashgit apply --check tmp/selected.patch -
使用 verbose 模式查看具体情况:bash
git apply --cached -v tmp/selected.patch -
常见错误信息:
- "patch does not apply":行数计数错误或上下文不匹配
- "patch fragment without header":缺少 或
diff --git行---/+++