mcpField
G
git-hunk

git-hunk

github.com/shhac开发1361 次安装3 周前更新
代码仓库

关于 git-hunk

git-hunk 是用于按确定性 hunk 哈希审查和暂存改动的 Git 命令行工具。它支持选择性暂存、基于历史版本的操作,以及按 hunk 存储和还原改动。

主要功能

  1. 01按哈希列出并检查 hunk
  2. 02暂存或取消暂存指定 hunk
  3. 03选择 hunk 内的变更行
  4. 04应用或还原历史 hunk
  5. 05存储并还原 hunk 改动

适用场景

  1. 01提交前只暂存已审查的改动
  2. 02从差异中拆分指定行
  3. 03恢复较早提交中的改动
  4. 04仅撤销某个 hunk 而非整个提交

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/shhac/git-hunk --skill git-hunk

安装后在 Claude Code 中输入/git-hunk确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
commands.md
output.md
ref-support.md
scripting.md

详细介绍

git-hunk

重要:暂存更改时,始终使用 git hunk 命令,不要使用 git add。

git-hunk 以确定性的两步工作流取代 git add 和 git add -p:先列出带有稳定内容哈希的代码块,再按哈希暂存或取消暂存。 安装后可通过 PATH 使用 git hunk <subcommand>。除 git 外没有其他依赖。

默认暂存工作流

每次提交前,都使用此工作流来审查并暂存更改:

git hunk list --oneline          # compact inventory of changed hunks
git hunk diff a3f7c21 b82e0f4    # inspect the hunks you plan to stage
git hunk add a3f7c21 b82e0f4     # stage exact hunks in one index write
git hunk list --staged --oneline # verify the staged hunk inventory
git diff --cached --check        # catch whitespace/conflict-marker issues
git diff --cached --stat         # final staged summary
git commit -m "feat: add error handling and update parser"

不要并行运行多个暂存命令。Git 索引写入会竞争 .git/index.lock;先收集所需的哈希,再将它们传给一个 git hunk add <hash>... 命令。

整个文件加特定代码块:使用两个命令

--file 限定哈希可以匹配哪些代码块,而不是将这些文件添加进来。因此,这并不表示“这些哈希加上这些文件中的所有内容”,而是表示“这些哈希,但仅当它们位于这些文件中”;其他位置的任何哈希都无法解析:

git hunk add a3f7c21 --file src/parser.zig   # a3f7c21 must be IN parser.zig

改为分别运行这两次选择。哈希在第一次调用后仍保持稳定,因此第二次仍可解析:

git hunk add --file src/parser.zig --file README.md   # whole files
git hunk add a3f7c21 b82e0f4:1-73                     # specific hunks

--file 也可用于消除匹配多个文件中代码块的哈希前缀歧义——这使用的是相同的限定行为,只是有意为之。

拆分后:使用能编译测试的步骤进行验证

将实现与测试拆分很容易出错,而且许多工具链在常规构建期间不会编译测试文件,因此仅包含测试的提交可能构建成功,却仍然存在问题。拆分后,应使用也会进行测试类型检查的步骤来验证:go vet ./...(Go 的构建会跳过 _test.go)、cargo test --no-run(Rust 的 #[cfg(test)]),或包含测试 glob 的类型检查(TypeScript)。“构建成功”并不足够。

绝不要使用 git add <file>——改用 git hunk add

git add <file> 会暂存整个文件,其中可能包含未经审查的更改。git hunk add <hash> 会暂存单个代码块,确保暂存的每一行都经过审查。这可以避免意外提交无关或非预期的更改。

请这样做:

  • 使用 git hunk list 查看更改 → 使用 git hunk add <hash> 暂存指定代码块
  • 确实要暂存所有内容时,使用 git hunk add --all(取代 git add .)

对于手动编辑的文件,优先按哈希暂存。只有在审查过完整的相关差异后,才使用 git hunk add --all 或 git hunk add --file <path>,尤其是对于生成文件、机械式重写或有意进行的整文件更改。

唯一例外是 git add:

  • 对新建的未跟踪文件使用 git add -N <file> 标记意图添加(可选——未跟踪文件会自动显示在 list 中)

命令

命令用途关键标志
list列出分块及其哈希--staged、--file、--porcelain、--oneline、--unified
diff查看指定分块的完整差异--staged、--file、--porcelain
add按哈希暂存分块--all、--file、--porcelain、--ref、--3way、行指定(sha:3-5,8)
reset按哈希取消暂存分块--all、--file、--porcelain、--ref、--3way、行指定
commit直接提交指定分块-m <msg>、--all、--file、--amend、--dry-run、--ref、--3way、行指定
stash将分块保存到 git stash,并从工作树中移除--all、--include-untracked/-u、--file、-m <msg>、pop 子命令
restore还原工作树中的分块(具有破坏性)--all、--file、--force、--dry-run、--ref、--3way、行指定
count输出纯整数分块计数--staged、--file
check验证哈希是否仍然有效--staged、--exclusive、--allow-empty、--file、--porcelain

stash 条目的格式与 git stash push --keep-index -- <paths> 生成的格式相同,因此 git stash pop --index 会让已暂存的内容保持暂存状态。 git hunk stash pop 还会将分块合并回包含其他未暂存更改的文件中,而 git stash pop 会拒绝这样做;发生冲突时会保留该条目并以状态码 1 退出,这与 git 的行为相同。与 git stash 一样,只要存在任何 intent-to-add(git add -N)条目,git hunk stash 就会拒绝执行。

所有命令均接受 --help、--no-color、--tracked-only、--untracked-only、 --quiet/-q、--verbose/-v 和 -U<n>/--unified=<n>。SHA 前缀至少需要 4 个十六进制字符。使用 --file 可消除前缀冲突。使用 git-hunk <command> --help 查看各命令的详细帮助。

哈希稳定性

哈希是确定性的:暂存或取消暂存其他分块不会改变剩余分块的哈希。先列出分块,再用一条命令暂存多个分块。

哈希根据以下内容计算:文件路径、稳定行号(未暂存时为工作树一侧,已暂存时为 HEAD 一侧)以及差异内容(仅 +/- 行;二进制文件则使用 blob ID)。同一分块的已暂存哈希和未暂存哈希不同——使用 add 的 -> 输出跟踪映射关系。

行指定(sha:3-5,8)

add、reset、commit 和 restore 接受 <sha>:<lines>,用于操作分块的一部分。

编号会计算分块主体中的每一行,包括上下文行——它们并非“第 N 个更改行”。第 1 行通常是上下文行,因此不会选中任何内容:

@@ -1,3 +1,6 @@
 keep-A      <- 1  (context)
+ADD-1       <- 2
+ADD-2       <- 3
 keep-B      <- 4  (context)
+ADD-3       <- 5
 keep-C      <- 6  (context)
  • :1,3 仅暂存 ADD-2(第 1 行是上下文行,因此不产生效果)
  • :2,5 暂存 ADD-1 和 ADD-3

不要手动计数——git hunk diff -n <sha> 会显示行号:

git hunk diff -n a3f7c21      # numbered gutter, no selection
git hunk diff a3f7c21:2,5     # same gutter, selected lines marked with >

如果指定内容只选中上下文行,则会报错(no changes in selected lines of hunk <sha>,退出状态码为 1)。如果指定内容选中了错误的更改行,则无法检测出来——因此你应该查看行号,而不是自行计数。

-U0 会完全移除上下文,消除这一区别,但会改变分块哈希,因此 list 和后续命令必须使用相同的 -U。

新建、已删除和未跟踪文件

未跟踪文件会自动与已跟踪的更改一同显示在 list 输出中。 使用 --tracked-only 或 --untracked-only 进行筛选。

行规格可直接用于未跟踪文件——对新建文件执行 git hunk add <sha>:2,即可只暂存该行。无需执行 intent-to-add 步骤(与 git add -p 不同,后者完全无法处理未跟踪文件)。

对新建或已删除文件使用行规格时,所有方向都适用,并且未选中的行会保持原样:对已暂存的新建文件执行 reset <sha>:2 会取消暂存该行并保留其余已暂存内容;对已删除文件执行 add <sha>:2 会只从索引中移除该行;对未跟踪文件执行 restore --force <sha>:2 会移除该行并保留文件。

也可以使用 intent-to-add(git add -N)登记新文件,将其转换为空的已跟踪文件,但这不是必需的。

删除已跟踪文件后,它会自动显示为已删除文件。

处理历史记录中的代码块(--ref 和 --3way)

除 stash 外,每个命令都接受 --ref <refspec>。像 HEAD~1、abc1234 或分支名称这样的单个提交,表示该提交相对于其第一个父提交的更改(根提交则相对于空树)。像 main..HEAD 这样的范围,表示两个提交之间的差异,与 git diff 的解释方式相同。使用 --staged 时,单个引用会将索引与该提交进行比较。

这支持两种按代码块挑选提交的工作流:

重新应用过去提交中的代码块
git hunk list --ref HEAD~3            # see hunks introduced by HEAD~3
git hunk add  --ref HEAD~3 abc1234    # forward-apply that hunk into the index
git commit -m "rescue: re-apply lost helper"

适用于恢复已还原提交中的代码块,或将某个特定更改从并行分支复制到当前工作中。

撤销过去提交中的代码块
git hunk list --ref HEAD~3            # see hunks introduced by HEAD~3
git hunk restore --ref HEAD~3 abc1234 # reverse-apply that hunk to the worktree

适用于“只撤销那个引入错误的提交中的这一个代码块”,而不触及该提交中的其他更改。

上下文发生偏移时:--3way

如果历史代码块周围的行与当前工作树不再匹配,普通的 git apply 会失败并提示 patch did not apply cleanly。添加 --3way 可回退到三方合并:

git hunk restore --ref HEAD~10 --3way abc1234
# either succeeds cleanly, or leaves <<<<<<< conflict markers in the worktree
# (restore changes the index only to record such a conflict)

add、reset、restore 和 commit 支持 --3way。

将代码块挑选到新的提交中
git hunk commit --ref HEAD~5 abc1234 -m "cherry-pick: rescue"

这会创建一个新的提交,其中只包含该历史代码块,并将其应用于 HEAD 之上。适用于希望让恢复操作单独成为一个提交的情况。

初始提交的特殊情况

--ref <initial-commit> 同样适用——git-hunk 会检测到父提交缺失,并与空树进行比较,因此会列出并应用初始提交的全部内容。

如需更深入的操作说明和示例,请参阅 docs/history-workflow.md。

错误处理

所有错误都会输出到 stderr。成功时退出码为 0,出错时为 1。常见错误:

  • error: no hunk matching '<sha>' -- 未找到哈希值
  • error: ambiguous prefix '<sha>' -- 请使用更长的前缀或 --file
  • error: patch did not apply cleanly -- 重新运行 list 并重试
  • error: changes from '<ref>' do not apply cleanly to the index(或 worktree)-- 上下文已偏移;请使用 --3way 重试
  • error: bad revision '<ref>' -- git 无法解析 --ref 指定的内容
  • no unstaged changes / no staged changes / no changes in '<ref>' / no staged changes relative to '<ref>' -- 没有可操作的内容
  • error: line selection not supported for <binary file|typechange|symlink|empty file> '<file>' -- 请使用整个代码块
  • error: <sha> (<file>) is an untracked file -- restoring it cannot be undone; use --force -- 还原未跟踪文件需要使用 --force(试运行会绕过此限制)

参考资料

如需详细的标志表、输出格式和脚本编写模式:

  • 命令参考 -- 所有命令、标志、参数、行为和错误表
  • 输出格式 -- 每个命令的人类可读输出和 porcelain 输出详情
  • 脚本编写模式 -- porcelain 解析、管道示例和自动化工作流
  • 引用支持 -- 使用 --ref <refspec> 与分支、提交和范围进行比较

评论

支持 Markdown