mcpField
G
git-hunk

git-hunk

github.com/shhac開発1361 回インストール3 週間前に更新
リポジトリ

git-hunk について

git-hunk は、決定的な hunk ハッシュを使って変更を確認・ステージする Git コマンドラインツールです。選択的なステージング、履歴上の変更操作、hunk 単位の stash と復元に対応します。

主な機能

  1. 01ハッシュによる hunk の一覧と確認
  2. 02指定 hunk のステージと解除
  3. 03hunk 内の変更行の選択
  4. 04履歴上の hunk の適用と復元
  5. 05hunk 変更の stash と復元

活用シーン

  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 add ではなく git hunk コマンドを使用してください。

git-hunk は git add と git add -p を、決定性のある2段階のワークフローに置き換えます。まず安定したコンテンツハッシュでハンクを列挙し、次にハッシュを指定してステージ/ステージ解除します。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 を取り合うため、対象のハッシュを集めて、1つの git hunk add <hash>... コマンドに渡してください。

ファイル全体と特定のハンク:2つのコマンドを使用する

--file は、ハッシュが照合できるハンクの範囲を指定するものであり、ハンクを追加するものではありません。つまり、これは「これらのハッシュに加えて、これらのファイル内のすべて」を意味するのではなく、「これらのファイル内にある場合に限り、これらのハッシュを対象とする」という意味です。ほかの場所にあるハッシュは解決されません。

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

代わりに、2つの選択を別々のコマンドとして実行してください。最初の呼び出しの後もハッシュは安定しているため、2回目も解決できます。

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 の唯一の例外:

  • 新しい未追跡ファイルを intent-to-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 はこれを拒否します。競合が発生するとエントリーは保持され、git の場合と同様に終了コード 1 で終了します。git stash と同様に、git add -N による intent-to-add エントリーがある場合、git hunk stash は実行できません。

すべてのコマンドで、--help、--no-color、--tracked-only、--untracked-only、 --quiet/-q、--verbose/-v、-U<n>/--unified=<n> を使用できます。SHA プレフィックスは 4 桁以上の 16 進数である必要があります。プレフィックスが衝突する場合は --file を使用して対象を特定してください。コマンドごとの詳細なヘルプを確認するには、git-hunk <command> --help を使用してください。

ハッシュの安定性

ハッシュは決定的です。他のハンクをステージしたり、ステージ解除したりしても、残りのハッシュは変わりません。一度一覧表示してから、複数のハンクを 1 つのコマンドでまとめてステージしてください。

ハッシュは、ファイルパス、安定した行番号(ステージされていない場合は作業ツリー側、ステージ済みの場合は 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 を実行すると、その行だけがステージされます。git add -p では 未追跡ファイルを扱えないため必要となる intent-to-add の手順は不要です。

新規ファイルまたは削除済みファイルに対する行指定は、どの方向でも機能し、選択されていない 行は元の状態のまま残ります。ステージ済みの新規ファイルに対する 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 と同様に、2つのコミット間の差分です。--staged を指定した場合、 単一の ref はインデックスとそのコミットを比較します。

これにより、次の2つのハンク単位のチェリーピックワークフローが可能になります。

過去のコミットからハンクを再適用する
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"

取り消されたコミットからハンクを復元したり、並行して作業しているブランチから特定の変更を 1つだけ作業に取り込んだりする場合に便利です。

過去のコミットからハンクを取り消す
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 を追加すると、3-way マージに フォールバックします。

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)

--3way は add、reset、restore、commit でサポートされています。

ハンクを新しいコミットにチェリーピックする
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 が必要です(ドライランではこの制限を回避できます)

参考資料

フラグの詳細な一覧、出力形式、スクリプトのパターンについては、以下を参照してください。

コメント