Skip to content

Latest commit

 

History

History
64 lines (47 loc) · 10.9 KB

diff-processing.ja.md

File metadata and controls

64 lines (47 loc) · 10.9 KB

差分の処理とセキュリティ

git-sc が AI プロバイダーに何を送るか、ステージ済みの差分をどう整えるか、共有するつもりのないファイルやデータをプロンプトに入れないために何をしているかをまとめています。ここで触れる設定項目は configuration.ja.md で説明しています。

動作の仕組み

flowchart LR
    A[変更をステージ] --> B[差分取得]
    B --> C[フォーマット検出]
    C --> D[AIで生成]
    D --> E[確認してコミット]
Loading
  1. 環境確認: Git リポジトリと AI エージェントが使えるかを確認
  2. 設定読み込み: ~/.config/git-sc/config.toml から設定を読み込み
  3. 差分取得: ステージされた変更を取得(除外設定を適用)
  4. フォーマット検出: 過去のコミットまたはルールから検出
  5. 生成: AI に送信(フォールバック付き)
  6. コミット: 確認してコミットを作成

差分の処理

  • 空白やインデントの変更も送信対象に含め、空白だけの変更もコミット可能。改行コードの変更(LF ↔ CRLF)も残すため、CRLF に変換しただけのファイルが AI から変更なしに見えることはない
  • バイナリファイルは中身を送らず、[Binary] modified: <パス> のような 1 行の要約に置き換え
  • lock ファイルは本文を送らず、[Lockfile] modified: Cargo.lock のようにパスと変更種別(追加・変更・削除・rename・copy)だけを送信。rename・copy は変更前後のパスを残し、パスに含まれる改行などの制御文字はエスケープ
  • スペースや非 ASCII 文字を含むパスの、クォートされた diff ヘッダーも正しく解析
  • .git-sc-ignore パターンに一致するファイルは、パスと本文を省略した旨だけを送信
  • 10,000 文字以内の差分は従来の形式を維持。それを超える場合は、全ファイルの一覧と追加・削除行数を残し、本文の 10,000 文字をファイルごとに配分。小さいファイルの余りは大きいファイルに再配分

lock ファイルの要約は設定不要で、通常のコミット・amend・squash・reword・--generate-for に適用します。対象は任意のディレクトリにある *.lock、*.lockb、*.lockfile、package-lock.json、npm-shrinkwrap.json、pnpm-lock.yaml、go.sum、Package.resolved です。.lock・.lockb・.lockfile というファイル名自体も対象です。Cargo.lock、yarn.lock、Gemfile.lock、composer.lock、uv.lock、bun.lock などは拡張子で判定されます。

要約は文字数制限の適用前に行うため、大きな lock ファイルの本文で他のファイルの差分が切り詰められるのを防げます。lock ファイルだけの変更でも生成できます。.git-sc-ignore に指定した場合は、lock ファイルやバイナリファイルもパスと本文を省略した旨だけを残します。

大きな差分では、全ファイルの一覧と省略通知を本文予算の別枠で保持します。一覧だけで 10,000 文字を超えても削りません。行数は本文の除外前に元の差分から集計し、バイナリは行数の代わりに binary と表示します。rename・copy は変更前後のパスを残します。マージの combined diff は、親ごとの列を通じて表示された追加・削除行を一度ずつ数え、combined rows と明記します。

プロンプトには、本文を省略または短縮したファイル数も示します。この件数には除外対象・lock ファイル・バイナリも含みます。本文は可能な限り完全な行で区切り、CRLF の内容も残します。--generate-for は元の差分を結合してから一度だけ処理するため、後続コミットの全ファイルも一覧に残ります。異なるコミットで同じパスが変わった場合は、それぞれの変更を別の行に表示します。開発ログのファイル数は一覧から集計し、本文のヘッダーを重複して数えません。

本文を短縮したファイルの一覧行には [body truncated] を付けます。Apple Intelligence は、端末内モデルの小さいコンテキスト枠に収めるため、さらに一覧と本文を縮めることがあります。この追加処理では、一覧から省いたファイル数を通知します。

セキュリティメモ

  • AI へのプロンプトには、ステージ済みの差分の内容が含まれることがあります。opencode などのプロバイダー向けに一時的なプロンプトファイルが必要な場合や、Codex の最終応答ファイルを使う場合は、Unix/macOS では group/other の権限を付けずに作成し、使用後に自動で削除します。
  • reword 用コミットメッセージの一時ファイルも同じ権限で作成します。
  • プロバイダーのクールダウン状態ファイル(~/.config/git-sc/.providers-state)も group/other の権限を付けずに作成します。クールダウンキーには各ステップの env の値がそのまま含まれるためです。
  • .git-sc-ignore の読み込みに失敗した場合は処理を中止します。 リンク切れも含め、ファイルが存在するのに読めない・解釈できない場合はエラーで終了します。そのまま続行すると、除外したかったファイルが黙って AI プロバイダーへ送られてしまうためです。
  • リポジトリのルートパスは、末尾の空白や改行も維持します。ディレクトリ名にこれらの文字が含まれていても、サブディレクトリからの実行を含め、プロジェクト設定と除外設定が適用されます。
  • 過去の件名と差分を取得するときは、log.showSignature にかかわらず署名検証の出力を省きます。署名者の情報や検証結果がコミットメッセージの参考情報に混ざるのを防ぎます。
  • --generate-for に注釈付きタグを渡した場合も、送るのはタグが指すコミットの差分だけです。タグオブジェクト自体(タグを付けた人の名前とメールアドレス、タグのメッセージ)は含めません。
  • .git-sc-ignore は diff の表示形式に関する Git 設定の影響を受けません。 除外判定は diff --git a/… b/… 行からファイルパスを読んで行います。そのため、この行の形を変える設定(diff.noprefix / diff.mnemonicPrefix / diff.srcPrefix / diff.dstPrefix / color.ui = always / diff.external)がそのまま効くと、パターンが黙って一切マッチしなくなります。git-sc は diff を取得するときにプレフィックス・色・パスの基準を固定して要求するので、これらの設定があってもパターンは同じように適用されます。diff.relative も同様です。この設定には「git-sc を実行したディレクトリの外にある変更を diff から隠す」作用もありますが、基準を固定しているため、どのサブディレクトリで実行してもステージ済みの差分全体からメッセージが書かれます。サブモジュール関連の設定も固定しています。diff.submodule = log はサブモジュールのブロックヘッダーの形を変えるため、固定しなければそのブロックにパターンがマッチしなくなります。diff.ignoreSubmodules = all は、ステージ済みのサブモジュールのポインター変更を diff からもステージ確認からも消してしまうため、固定しなければ --squash が AI の見ていない変更まで畳み込むおそれがあります。同じ効果の設定は、自分の Git 設定だけでなく、リポジトリにコミットされた .gitmodules から入ってくることもあります。
  • プロジェクトの .git-sc はコードを実行できます。 providers[].command、prefix_scripts[].script、ai_usage.command は git-sc が起動する実行ファイルを指定する項目で、リポジトリ内の .git-sc もほかの設定と同じようにマージされます。信頼できないリポジトリを clone してその中で git-sc を実行すると(エージェントの Stop フック経由の自動実行を含む)、これらが指す実行ファイルが動きます。env のキーは検証され、動的ローダーやインタープリターの事前ロード系のキーは拒否されますが、この 3 つの項目はその対象外です。Makefile や Git フックと同じように、実行前にそのリポジトリの .git-sc を確認してください。

.git-sc-ignore

一致するファイルは、元の diff ヘッダー(ファイルパス、rename では変更前後のパス)と [content omitted by .git-sc-ignore] だけを AI に送ります。本文と、それ以外の diff メタデータは省略します。通常のコミット・amend・squash・reword・--generate-for に共通で適用するため、変更がすべて除外対象でもパスを基にメッセージを生成できます。否定パターン(!)を使うと、選んだファイルの本文を再び送信対象にできます。

.git-sc-ignore は Git リポジトリのルートに置き、gitignore 形式のパターンを書きます。Git が日本語のファイル名などをエスケープしてクォートしていても、元に戻した実際のパスでパターンを照合します。rename の diff では変更前と変更後の両方のパスを照合するため、無視対象のディレクトリへの移動も同じように除外されます。パスに b/ を含む場合(plan b という名前のディレクトリなど)は、クォートされない rename のヘッダーから境界を一意に決められませんが、rename from / rename to の行のパスも照合するので、除外は外れません。ファイル名にスペースを含む場合にも対応しています。Git は、ほかに特殊な文字がなくスペースを含むだけのファイル名を、クォートせずに diff --git ヘッダーへ出力します。git-sc はその場合も正しいパスを取り出すので、無視パターンは同じように適用されます。変更前後のパスが異なり、両方にスペースを含む rename ヘッダーも同じように処理します。片側だけがクォートされる混在ヘッダー(例: old name.txt を Git がクォートする非 ASCII ファイル名へ rename した場合)も両方向に対応しています。

package-lock.json
yarn.lock
Cargo.lock
*.generated.ts