Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Git の使用

Rust プロジェクトでは、ソースコードの管理に Git を使用しています。 コントリビュートするには、自分の変更をコンパイラに取り込めるようにするため、 Git の機能にある程度慣れている必要があります。

このページの目的は、新しいコントリビューターが直面しがちな、より一般的な質問や 問題をいくつか取り上げることです。 ここでも Git の基本をいくつか扱いますが、 それでも少し進みが速いと感じる場合は、まず Atlassian のこのチュートリアルの 「Beginner」や「Getting started」セクションなど、Git の入門記事を読むとよいでしょう。 GitHub も初心者向けのドキュメントガイドを提供しています。 また、より詳しい Git の書籍を参照することもできます。

このガイドは完全ではありません。 このページでは解決できない git の問題に遭遇した場合は、 修正方法を文書化できるように、issue を開いてください

前提条件

Git をインストールし、rust-lang/rust をフォークし、フォークしたリポジトリを 自分の PC にクローン済みであるものとします。 Git とのやり取りにはコマンドラインインターフェイスを使用します。 一般的には同じことができる GUI や IDE 連携も数多くあります。

フォークをクローンしている場合、ローカルリポジトリではそれを origin として参照できます。 次のようにして、公式の rust-lang/rust リポジトリ用のリモートも設定しておくと便利かもしれません。

git remote add upstream https://github.com/rust-lang/rust.git

HTTPS を使用している場合、または

git remote add upstream git@github.com:rust-lang/rust.git

SSH を使用している場合です。

注: このページは rust-lang/rust 向けのワークフローを扱っていますが、 Rust プロジェクト内の他のリポジトリへコントリビュートする際にも役立つ可能性があります。

標準的な手順

以下は、ほとんどの小さな変更や PR で使用することになる通常の手順です。

  1. main を基点に変更を加えていることを確認します: git checkout main
  2. Rust リポジトリから最新の変更を取得します: git pull upstream main --ff-only。 (これについての詳細はマージ禁止ポリシーを参照してください)。
  3. 変更用の新しいブランチを作成します: git checkout -b issue-12345-fix
  4. リポジトリに変更を加え、テストします。
  5. git add src/changed/file.rs src/another/change.rs で変更をステージし、 その後 git commit でコミットします。 もちろん、中間コミットを作成するのもよい考えです。 git add . は避けてください。サブモジュールの更新など、 コミットすべきでない変更を意図せずコミットしてしまいやすくなるためです。 ステージし忘れたファイルがないか確認するには、git status を使用できます。
  6. 変更を自分のフォークへプッシュします: git push --set-upstream origin issue-12345-fix (コミットを追加した後は git push を使用でき、リベースまたは pull-and-rebase の後は git push --force-with-lease を使用できます)。
  7. 自分のフォークから rust-lang/rustmain ブランチへ PR を開きます

最終的にリベースが必要になり、コンフリクトに遭遇している場合は、リベースを参照してください。 長期間続く機能や issue に取り組んでいる間に upstream を追跡したい場合は、 最新の状態に保つを参照してください。

レビュー担当者から変更を求められた場合、その変更の手順もほぼ同じですが、 いくつかの手順は省かれます。

  1. 自分のコードの最新バージョンに対して変更を加えていることを確認します: git checkout issue-12345-fix
  2. 以前と同じように、追加の変更を行い、ステージし、コミットします。
  3. それらの変更を自分のフォークへプッシュします: git push

git の問題のトラブルシューティング

rust-lang/rust が古くなっていても、最初からクローンし直す必要はありません! 修復できないほど壊してしまったと思っていても、リポジトリ全体を再度ダウンロードせずに git の状態を修正する方法があります。 遭遇する可能性のある一般的な問題をいくつか示します。

誤ってマージコミットを作成してしまいました。

Git には、ブランチを最新の変更で更新する方法が 2 つあります。マージとリベースです。 Rust はリベースを使用しています。 マージコミットを作成してしまっても、修正はそれほど難しくありません: git rebase -i upstream/main

リベースの詳細については、リベースを参照してください。

GitHub 上の自分のフォークを削除してしまいました!

これは git の観点では問題ではありません。 git remote -v を実行すると、 次のような内容が表示されます。

$ git remote -v
origin  git@github.com:jyn514/rust.git (fetch)
origin  git@github.com:jyn514/rust.git (push)
upstream        https://github.com/rust-lang/rust (fetch)
upstream        https://github.com/rust-lang/rust (fetch)

フォークの名前を変更した場合は、次のように URL を変更できます。

git remote set-url origin <URL>

ここで <URL> は新しいフォークです。

誤ってサブモジュールを変更してしまいました

通常、これは cargo が変更されたと rustbot が GitHub にコメントを投稿したときに気づきます。

rustbot のサブモジュールコメント

Web UI でコンフリクトに気づく場合もあります。

src/tools/cargo のコンフリクト

最も一般的な原因は、変更後にリベースし、サブモジュールを更新するための x を先に実行せずに git add . を実行したことです。 あるいは、x fmt ではなく cargo fmt を実行し、 サブモジュール内のファイルを変更してから、その変更をコミットした可能性もあります。

修正するには、次のことを行います(cargo 以外のサブモジュールを変更した場合は、 src/tools/cargo をそのサブモジュールへのパスに置き換えてください)。

  1. 誤った変更が含まれているコミットを確認します: git log --stat -n1 src/tools/cargo
  2. そのコミットに対する変更を取り消します: git checkout <my-commit>~ src/tools/cargo~ はそのまま入力しますが、<my-commit> は手順 1 の出力に置き換えてください。
  3. git に変更をコミットするよう指示します: git commit --fixup <my-commit>
  4. 変更したすべてのサブモジュールについて、手順 1〜3 を繰り返します。
    • 複数の異なるコミットでサブモジュールを変更した場合は、変更した各コミットについて 手順 1〜3 を繰り返す必要があります。 git log コマンドが自分の作成者ではないコミットを表示したときに、 そこで止めればよいことが分かります。
  5. 変更を既存のコミットに squash します: git rebase --autosquash -i upstream/main
  6. 変更をプッシュします

リベースしようとすると “error: cannot rebase” が表示されます

リベース時によく見られるエラーは次の 2 つです。

error: cannot rebase: Your index contains uncommitted changes.
error: Please commit or stash them.
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.

(この 2 つの違いについては https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F#_the_three_states を参照してください。) これは、前回コミットした時点から変更を加えていることを意味します。 リベースできるようにするには、 変更をコミットするか、リベースを完了したときにそれらをまだコミットされていない状態にしておくために “stash” と呼ばれる一時的なコミットを作成します。 git がこの “stash” を自動的に作成するように設定したい場合があります。これにより、 ほぼすべての場合で “cannot rebase” エラーを防げます。

git config --global rebase.autostash true

stash の詳細については、https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning を参照してください。

‘Untracked Files: src/stdarch’ が表示されますか?

これは library/ ディレクトリへの移動の名残です。 残念ながら、git rebase はサブモジュールのリネームを追跡しないため、 自分でディレクトリを削除する必要があります。

rm -r src/stdarch

<<< HEAD が表示されますか?

おそらく、リベースまたはマージ競合の途中だったのでしょう。 競合を修正する方法については、競合 を参照してください。 変更内容を気にせず、 リポジトリのクリーンなコピーを取り戻したいだけであれば、git reset を使用できます。

# 警告: これにより、あなたが行ったローカルの変更はすべて破棄されます! 代わりに競合を解決することを検討してください。
git reset --hard main

failed to push some refs

git push は正しく動作せず、次のようなことを言います。

 ! [rejected]        issue-xxxxx -> issue-xxxxx (non-fast-forward)
error: failed to push some refs to 'https://github.com/username/rust.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

ここで示されるアドバイスは正しくありません! Rust の “no-merge” ポリシー により、git pull によって作成されるマージコミットは 最終的な PR では許可されませんし、そもそもリベースの目的も損なってしまいます! 代わりに git push --force-with-lease を使用してください。

Git が自分で書いていないコミットをリベースしようとしていますか?

リベースリストに多数のコミット、マージコミット、または自分で 書いていない他の人のコミットが表示される場合、おそらく間違ったブランチを対象にリベースしようとしています。 たとえば、rust-lang/rust のリモート upstream があるのに、git rebase upstream/main ではなく git rebase origin/main を実行したのかもしれません。 修正方法は、リベースを中止し、代わりに正しいブランチを使用することです。

git rebase --abort
git rebase --interactive upstream/main
間違ったブランチを対象にリベースした例を見るには、ここをクリックしてください

間違ったブランチを対象にしたインタラクティブリベース

サブモジュールに関する簡単な注意

git pull でローカルリポジトリを更新すると、自分が一度も編集していないファイルを 変更したと Git が言うことに気づく場合があります。 たとえば、 git status を実行すると次のような出力になります(new commits という言及に注意してください)。

On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   src/llvm-project (new commits)
	modified:   src/tools/cargo (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

これらの変更はファイルへの変更ではなく、サブモジュールへの変更です(これについては後ほど詳しく説明します)。 これらを取り除くには、次を実行します。

git submodule update

一部のサブモジュールは実際には必要ありません。たとえば、download-ci-llvm を使用している場合、 src/llvm-project をチェックアウトする必要はありません。 その履歴を取得し続けなくて済むようにするには、 git submodule deinit -f src/llvm-project を使用できます。これにより、再び変更済みとして表示されることも避けられます。

リベースと競合

ローカルでコードを編集するとき、フィーチャーブランチを作成した時点で存在していた rust-lang/rust のバージョンに変更を加えています。 そのため、PR を提出すると、それ以降に rust-lang/rust に加えられた変更の一部が、 あなたの加えた変更と競合する可能性があります。 これが発生した場合、変更をマージできるようにする前に競合を解決する必要があります。 そのためには、自分の作業を rust-lang/rust の上にリベースする必要があります。

リベース

フィーチャーブランチを rust-lang/rust の main ブランチの最新バージョンの上に リベースするには、自分のブランチをチェックアウトしてから、次のコマンドを実行します。

git pull --rebase https://github.com/rust-lang/rust.git main

次のエラーが表示された場合:

error: cannot pull with rebase: Your index contains uncommitted changes.
error: please commit or stash them.

これは、ワーキングツリーに未コミットの作業があることを意味します。その 場合は、リベースする前に git stash を実行し、リベースしてすべての競合を 修正した後に git stash pop を実行してください。

ブランチを main にリベースすると、そのブランチ上のすべての変更が main の最新バージョンに再適用されます。 言い換えると、Git は、 古いバージョンの main に対して行った変更が、代わりに新しいバージョンの main に 対して行われたかのように見せようとします。 この処理中には、少なくとも 1 つの「リベース競合」に遭遇することを想定しておくべきです。 これは、あなたの変更が他の加えられた変更と競合したために、 Git による変更の再適用が失敗したときに発生します。 次のような行が出力に表示されるため、これが発生したことがわかります。

CONFLICT (content): Merge conflict in file.rs

これらのファイルを開くと、次の形式のセクションが表示されます。

<<<<<<< HEAD
Original code
=======
Your code
>>>>>>> 8fbf656... Commit fixes 12345

これは、Git がどのようにリベースすればよいか判断できなかったファイル内の行を表しています。 <<<<<<< HEAD======= の間のセクションには main のコードがあり、反対側にはあなたのバージョンのコードがあります。 競合にどう対処するかを決める必要があります。 自分の変更を残したい場合もあれば、 main 上の変更を残したい場合、またはその 2 つを組み合わせたい場合もあります。

一般に、競合の解決は 2 つの手順で構成されます。まず、特定の競合を修正します。 ファイルを編集して望む変更を加え、その過程で <<<<<<<=======>>>>>>> の各行を削除します。 次に、周辺のコードを確認します。 競合があった場合、そこには論理的なエラーも潜んでいる可能性があります! ここで x check を実行して、明らかなエラーがないことを確認するのはよい考えです。

競合の修正がすべて完了したら、競合があったファイルを git add で ステージする必要があります。 その後、git rebase --continue を実行して、 競合を解決したのでリベースを完了してよいことを Git に知らせます。

リベースが成功したら、フォーク上の関連するブランチを git push --force-with-lease で更新します。

最新の状態に保つ

上記のセクションは、作業をリベースし、マージ競合に対処するための具体的な ガイドです。 ローカルリポジトリをアップストリームの変更に追従させて最新の状態に保つ方法について、一般的なアドバイスを以下に示します。 ローカルの main ブランチ上で定期的に git pull upstream main を使用すると、最新の状態を保てます。 フィーチャーブランチも最新の状態に保つ必要があります。 pull した後、フィーチャーブランチをチェックアウトしてリベースできます。

git checkout main
git pull upstream main --ff-only # マージコミットがないことを確実にするため
git rebase main feature_branch
git push --force-with-lease # (origin をローカルと同じ状態に設定する)

No-Merge Policy に従ってマージを避けるには、 git config pull.ff only を使用するとよいでしょう(これにより、設定はローカルリポジトリにのみ適用されます)。 これにより、毎回 --ff-only--rebase を渡さなくても、 git pull 時に Git がマージコミットを作成しないようにできます。

また、main から git push --force-with-lease を実行することで、 フィーチャーブランチが GitHub 側の状態と同期していることを再確認することもできます。

高度なリベース

コミットを squash する

コミットを互いに「squash」すると、それらは 1 つのコミットに統合されます。 これの利点でも欠点でもあるのは、履歴が単純化されることです。 一方では、変更が行われた手順を追跡できなくなりますが、 履歴は扱いやすくなります。

rust-lang/rust リポジトリの PR でコミットを squash する最も簡単な方法は、PR のコメントで @bors squash コマンドを使用することです。 デフォルトでは、bors は PR のすべてのコミットメッセージを squash 後のコミットメッセージに結合します。 コミットメッセージをカスタマイズするには、@bors squash msg="<commit message>" を使用します。 たとえば、@bors squash msg="Improve diagnostics for missing lifetime parameter" です。

ローカルの git 操作を使用してコミットを squash したい場合は、以下を読み進めてください。

コンフリクトがなく、履歴を整理するためだけに squash する場合は、 git rebase --interactive --keep-base main を使用します。 これにより、PR の分岐点が同じまま保たれるため、 リベースをまたいで何が起きたかの diff をレビューしやすくなります。

squash は、コンフリクト解決の一環としても役立つことがあります。 ブランチに同じコードの連続した複数の書き換えが含まれている場合、または リベースのコンフリクトが非常に深刻な場合は、 git rebase --interactive main を使用してプロセスをより細かく制御できます。 これにより、コミットをスキップするか、スキップしないコミットを編集するか、 適用される順序を変更するか、またはそれらを互いに「squash」するかを選択できます。

あるいは、次のようにしてコミット履歴を犠牲にすることもできます。

# すべての変更を 1 つのコミットに squash し、コンフリクトを 1 回だけ気にすればよいようにする
git rebase --interactive --keep-base main  # その過程ですべての変更を squash する
git rebase main
# すべてのマージコンフリクトを修正する
git rebase --continue

場合によっては、最後の数個のコミットだけをまとめて squash したいこともあります。 それらが実際の変更ではなく「fixup」だけを表している場合などです。 たとえば、 git rebase --interactive HEAD~2 を使用すると、2 つのコミットだけを編集できます。

git range-diff

リベースを完了した後、変更を push する前に、 古いブランチと新しいブランチの間の変更をレビューしたい場合があります。 これは git range-diff main @{upstream} HEAD で行えます。

range-diff の最初の引数、この場合は main は、 古いブランチと新しいブランチを比較する基準となるリビジョンです。 2 番目の引数は ブランチの古いバージョンです。この場合、@upstream は GitHub に push 済みのバージョンを意味し、これはプルリクエストで他の人が見るものと同じです。 最後に、range-diff の 3 番目の引数は ブランチの新しいバージョンです。この場合は HEAD であり、これは現在 ローカルリポジトリでチェックアウトされているコミットです。

同等の省略形である git range-diff main @{u} HEAD も使用できることに注意してください。

通常の Git diff とは異なり、range-diff の出力では、別の - または + の隣に - または + が表示されます。 左側のマーカーは 古いブランチと新しいブランチの間の変更を示し、右側のマーカーはコミットした変更を示します。 したがって、range-diff は「diff の diff」と考えることができます。 古い diff と新しい diff の間の違いを示すためです。

以下は git range-diff の出力例です(Git のドキュメントから取得):

-:  ------- > 1:  0ddba11 Prepare for the inevitable!
1:  c0debee = 2:  cab005e Add a helpful message at the start
2:  f00dbal ! 3:  decafe1 Describe a bug
    @@ -1,3 +1,3 @@
     Author: A U Thor <author@example.com>

    -TODO: Describe a bug
    +Describe a bug
    @@ -324,5 +324,6
      This is expected.

    -+What is unexpected is that it will also crash.
    ++Unexpectedly, it also crashes. This is a bug, and the jury is
    ++still out there how to fix it best. See ticket #314 for details.

      Contact
3:  bedead < -:  ------- TO-UNDO

(端末での git range-diff の出力は色が付くため、おそらくこの例よりも 読みやすいことに注意してください。)

git range-diff のもう 1 つの機能は、git diff とは異なり、コミットメッセージの diff も表示することです。 この機能は、複数のコミット メッセージを修正する際に、正しい箇所を変更したことを確認できるため便利です。

git range-diff は非常に便利なコマンドですが、その出力形式に慣れるには多少時間がかかることに注意してください。 また、このコマンドに関する Git のドキュメント、 特に “Examples” セクションも役立つかもしれません。

No-Merge Policy

rust-lang/rust リポジトリでは、「リベースワークフロー」として知られるものを使用しています。 これは、PR 内のマージコミットが受け入れられないことを意味します。 そのため、ローカルで git merge を実行している場合は、代わりにリベースすべき可能性が高いです。 もちろん、これは常に正しいわけではありません。git pull が通常行うマージのように、 マージが単なる fast-forward である場合、 マージコミットは作成されないため、心配する必要はありません。 一度 git config merge.ff only を実行すると(これにより、設定はローカルリポジトリに適用されます)、 実行するすべてのマージがこの種類であることが保証されるため、 ミスをすることができなくなります。

この決定にはいくつかの理由があり、他のすべてのものと同様に、これはトレードオフです。 主な利点は、一般的に線形なコミット履歴です。 これにより bisect が大幅に単純化され、履歴とコミットログがはるかに 追いやすく理解しやすくなります。

レビューのヒント

NOTE: このセクションは PR を作成するためではなく、レビューするためのものです。

空白を非表示にする

GitHub には、空白の変更を無効にするための便利なボタンがあります。 ローカルで変更を表示するには、git diff -w origin/main を使用することもできます。

空白を非表示にする

PR を取得する

PR をローカルにチェックアウトするには、git fetch upstream pull/NNNNN/head && git checkout FETCH_HEAD を使用できます。

github の CLI ツールを使用することもできます。 GitHub は PR 上にボタンを表示し、ローカルにチェックアウトするためのコマンドをコピー & ペーストできます。 詳細については https://cli.github.com/ を参照してください。

gh の提案

GitHub dev の使用

GitHub Web UI の代替として、GitHub Dev はリポジトリや PR を閲覧するための Web ベースのエディタを提供します。 URL の github.comgithub.dev に置き換えるか、 GitHub ページで . を押すことで開けます。 詳細については、github.dev エディタのドキュメント を参照してください。

大きなコードセクションの移動

ファイル内部での大きな移動に対する Git と GitHub のデフォルトの diff 表示はかなり貧弱です。各 行が削除済み、各行が追加済みとして表示されるため、各行を自分で比較する必要があります。 Git には、移動された行を別の色で表示するオプションがあります。

git log -p --color-moved=dimmed-zebra --color-moved-ws=allow-indentation-change

詳細については、--color-moved のドキュメントを参照してください。

range-diff

PR 作成者向けの関連セクションを参照してください。 これは、予期しない変更がないことを確認するために、 force-push されたコードを比較する際に役立ちます。

特定のファイルへの変更を無視する

リポジトリ内の多くの大きなファイルは自動生成されています。 それらのファイルへの変更を無視した diff を表示するには、 次の構文を使用できます(例: Cargo.lock)。

git log -p ':!Cargo.lock'

任意のパターンがサポートされています(例: :!compiler/*)。パターンは .gitignore と同じ構文を使用し、パターンであることを示すために先頭に : を付けます。

Git サブモジュール

注記: サブモジュールについて知っておくのは良いことですが、rustc にコントリビュートするための 絶対的な前提条件ではありません。 Git を初めて使用する場合は、 このセクションを読む前に Git の主要な概念に慣れておくとよいでしょう。

rust-lang/rust リポジトリでは、rust リポジトリ内から他の Rust プロジェクトを利用する方法として Git submodules を使用しています。 例として、Rust の llvm-project のフォーク、cargostdarchbacktrace のようなライブラリがあります。

これらのプロジェクトは別の Git(および GitHub)リポジトリで開発・保守されており、 それぞれ独自の Git 履歴/コミット、issue トラッカー、PR を持っています。 サブモジュールを使うと、rust リポジトリ内にある種の埋め込みサブリポジトリを作成し、 それらを rust リポジトリ内のディレクトリであるかのように使用できます。

llvm-project を例に考えてみましょう。 llvm-projectrust-lang/llvm-project リポジトリで保守されていますが、 rust-lang/rust ではコンパイラによるコード生成と最適化のために使用されています。 これを rust にはサブモジュールとして、src/llvm-project フォルダに取り込んでいます。

サブモジュールの内容は Git によって無視されます。サブモジュールはある意味で、 リポジトリの他の部分から分離されています。 しかし、cd src/llvm-project を実行してから git status を実行してみると、次のようになります。

HEAD detached at 9567f08afc943
nothing to commit, working tree clean

git から見ると、あなたはもはや rust リポジトリ内ではなく、llvm-project リポジトリ内にいます。 ここでは “detached HEAD” 状態、すなわちブランチ上ではなく 特定のコミット上にいることに気づくでしょう。

これは、あらゆる依存関係と同様に、使用するバージョンを制御できるようにしたいためです。 サブモジュールを使うと、まさにそれが可能になります。各サブモジュールは特定の コミットに「ピン留め」されており、手動で変更しない限り変わりません。 llvm-project ディレクトリで git checkout <commit> を使用し、 rust ディレクトリに戻ると、たとえば git add src/llvm-project を実行することで、この変更を 他の変更と同じようにステージできます。(なお、コミットするためにその変更をステージしない場合、 x を実行したときに、サブモジュールが自動的に「更新」される際に以前のコミットへ戻され、 変更が取り消されてしまうリスクがあります。)

このバージョン選択は通常、プロジェクトのメンテナーによって行われ、 こちらのようになります。

Git サブモジュールに慣れるには少し時間がかかるため、まだ完全に明確でなくても心配しないでください。 直接使わなければならないことはめったにありませんし、繰り返しになりますが、 Rust にコントリビュートするためにサブモジュールについてすべてを知っている必要はありません。 それらが存在し、Git がうまく、そしてかなり便利に扱ってくれる、ある種の埋め込みサブリポジトリ依存関係に 対応していることだけを知っておいてください。

サブモジュールを hard-reset する

ときどき(git status を実行したときに)次のような状況に遭遇することがあります。

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)
        modified:   src/llvm-project (new commits, modified content)

そして git submodule update を実行しようとすると、次のようなエラーでひどく壊れることがあります。

error: RPC failed; curl 92 HTTP/2 stream 7 was not closed cleanly: CANCEL (err 8)
error: 2782 bytes of body are still expected
fetch-pack: unexpected disconnect while reading sideband packet
fatal: early EOF
fatal: fetch-pack: invalid index-pack output
fatal: Fetched in submodule path 'src/llvm-project', but it did not contain 5a5152f653959d14d68613a3a8a033fb65eec021. Direct fetching of that commit failed.

(new commits, modified content) が表示される場合は、次を実行できます。

git submodule foreach git reset --hard

その後、もう一度 git submodule update を試してください。

git サブモジュールを deinit する

それでもうまくいかない場合は、すべての git サブモジュールを deinit してみることができます…

git submodule deinit -f --all

残念ながら、何らかの理由でローカルの git サブモジュール設定が 完全におかしくなってしまうことがあります。

fatal: not a git repository: <submodule>/../../.git/modules/<submodule> を克服する

ときどき、何か不運な理由で、次のような状況に遭遇することがあります。

fatal: not a git repository: src/gcc/../../.git/modules/src/gcc

この状況では、指定されたサブモジュールパス、すなわちこの例では <submodule_path> = src/gcc について、次を行う必要があります。

  1. rm -rf <submodule_path>/.git
  2. rm -rf .git/modules/<submodule_path>/config
  3. 何らかの理由で .gitconfig のロックが孤立している場合は、rm -rf .gitconfig.lock

その後、./x fmt のようなものを実行して、bootstrap にサブモジュールのチェックアウトを管理させます。

git blame 中にコミットを無視する

一部のコミットには、機能を変更しない大規模な再フォーマット変更が含まれています。 これらは、.git-blame-ignore-revs を通じて git blame に無視するよう指示できます。

  1. 無視するコミットの一覧として .git-blame-ignore-revs を使用するように git blame を設定します: git config blame.ignorerevsfile .git-blame-ignore-revs
  2. git blame に無視させたい適切なコミットを追加します。

.git-blame-ignore-revs に追加するコミットにはコメントを含めてください。そうすれば、そのコミットが なぜ無視されているのかを他の人が簡単に理解できます。