-
1. Gitを始めるにあたって
- 1.1 バージョン管理について
- 1.2 Gitの歴史
- 1.3 Gitとは何か?
- 1.4 コマンドライン
- 1.5 Gitのインストール
- 1.6 Gitの初回セットアップ
- 1.7 ヘルプの利用
- 1.8 まとめ
-
2. Gitの基本
- 2.1 Gitリポジトリの取得
- 2.2 リポジトリへの変更の記録
- 2.3 コミット履歴の表示
- 2.4 元に戻す操作
- 2.5 リモートでの作業
- 2.6 タグ付け
- 2.7 Gitエイリアス
- 2.8 まとめ
-
3. Gitのブランチ機能
- 3.1 ブランチの基本
- 3.2 基本的なブランチとマージ
- 3.3 ブランチ管理
- 3.4 ブランチワークフロー
- 3.5 リモートブランチ
- 3.6 リベース
- 3.7 まとめ
-
4. サーバー上のGit
- 4.1 プロトコル
- 4.2 サーバーにGitをセットアップする
- 4.3 SSH公開鍵の生成
- 4.4 サーバーのセットアップ
- 4.5 Gitデーモン
- 4.6 スマートHTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 サードパーティのホスティングオプション
- 4.10 まとめ
-
5. 分散Git
- 5.1 分散ワークフロー
- 5.2 プロジェクトへの貢献
- 5.3 プロジェクトの管理
- 5.4 まとめ
-
6. GitHub
- 6.1 アカウントのセットアップと設定
- 6.2 プロジェクトへの貢献
- 6.3 プロジェクトの管理
- 6.4 組織の管理
- 6.5 GitHubのスクリプト
- 6.6 まとめ
-
7. Gitツール
- 7.1 リビジョンの選択
- 7.2 インタラクティブステージング
- 7.3 スタッシュとクリーン
- 7.4 作業に署名する
- 7.5 検索
- 7.6 履歴の書き換え
- 7.7 Resetの解明
- 7.8 高度なマージ
- 7.9 Rerere
- 7.10 Gitを使ったデバッグ
- 7.11 サブモジュール
- 7.12 バンドル
- 7.13 置換
- 7.14 認証情報の保存
- 7.15 まとめ
-
8. Gitのカスタマイズ
- 8.1 Gitの設定
- 8.2 Git属性
- 8.3 Gitフック
- 8.4 Gitによるポリシー適用例
- 8.5 まとめ
-
9. Gitと他のシステム
- 9.1 クライアントとしてのGit
- 9.2 Gitへの移行
- 9.3 まとめ
-
10. Gitの内側
- 10.1 PlumbingとPorcelain
- 10.2 Gitオブジェクト
- 10.3 Gitリファレンス
- 10.4 Packfile
- 10.5 Refspec
- 10.6 転送プロトコル
- 10.7 メンテナンスとデータ復旧
- 10.8 環境変数
- 10.9 まとめ
-
A1. 付録A: 他の環境でのGit
- A1.1 グラフィカルインターフェース
- A1.2 Visual StudioでのGit
- A1.3 Visual Studio CodeでのGit
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMineでのGit
- A1.5 Sublime TextでのGit
- A1.6 BashでのGit
- A1.7 ZshでのGit
- A1.8 PowerShellでのGit
- A1.9 まとめ
-
A2. 付録B: アプリケーションへのGitの組み込み
- A2.1 コマンドラインGit
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. 付録C: Gitコマンド
- A3.1 セットアップと設定
- A3.2 プロジェクトの取得と作成
- A3.3 基本的なスナップショット
- A3.4 ブランチとマージ
- A3.5 プロジェクトの共有と更新
- A3.6 検査と比較
- A3.7 デバッグ
- A3.8 パッチ適用
- A3.9 メール
- A3.10 外部システム
- A3.11 管理
- A3.12 Plumbingコマンド
7.9 Git ツール - Rerere
Rerere
git rerere
機能は、少し隠れた機能です。この名前は「reuse recorded resolution (記録された解決策の再利用)」の略であり、その名の通り、Git に対してチャンクのコンフリクトをどのように解決したかを記憶させ、次回同じコンフリクトが発生した際に Git が自動的に解決できるようにする機能です。
この機能は、様々なシナリオで非常に便利です。ドキュメントで言及されている例の1つは、長期にわたるトピックブランチが最終的にクリーンにマージされることを確認したいが、大量の中間マージコミットでコミット履歴を汚したくない場合です。rerere
を有効にすると、時折マージを試み、コンフリクトを解決し、その後マージを取り消すことができます。これを継続的に行うと、rerere
がすべて自動的に処理してくれるため、最終的なマージは簡単になるはずです。
この同じ戦術は、ブランチをリベースし続けることで、リベースするたびに同じリベースのコンフリクトに対処する必要がなくなる場合にも使用できます。または、マージして多数のコンフリクトを修正したブランチを、代わりにリベースすることにした場合でも、おそらく同じコンフリクトをすべて再度行う必要はありません。
rerere
のもう一つの応用例は、Git プロジェクト自身がよく行うように、多数の進化するトピックブランチをたまにテスト可能なヘッドにマージする場合です。テストが失敗した場合、コンフリクトを再解決することなく、テストを失敗させたトピックブランチなしでマージを巻き戻してやり直すことができます。
rerere
機能を有効にするには、以下の設定を実行するだけです。
$ git config --global rerere.enabled true
特定のレポジトリに .git/rr-cache
ディレクトリを作成することでも有効にできますが、設定の方がより明確で、その機能をグローバルに有効にします。
では、以前の例と同様の簡単な例を見てみましょう。以下のような hello.rb
というファイルがあるとします。
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
片方のブランチで「hello」という単語を「hola」に変更し、もう一方のブランチで「world」を「mundo」に変更します。これは以前と同じです。

2つのブランチをマージすると、マージコンフリクトが発生します。
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
Recorded preimage for FILE
という新しい行に気づくはずです。それ以外は、通常のマージコンフリクトとまったく同じに見えるはずです。この時点で、rerere
はいくつかのことを教えてくれます。通常、この時点で git status
を実行して、何がコンフリクトしたかを確認するかもしれません。
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
しかし、git rerere status
を使用すると、git rerere
がマージ前の状態を記録したものを教えてくれます。
$ git rerere status
hello.rb
そして、git rerere diff
は解決の現在の状態、つまり解決を始めたものと、解決したものを示します。
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
また(これは rerere
とはあまり関係ありませんが)、git ls-files -u
を使用して、コンフリクトしているファイルと、その前、左、右のバージョンを確認できます。
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
これで「puts 'hola mundo'」と解決し、再度 git rerere diff
を実行して rerere が何を記憶するかを確認できます。
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
つまり、Git が hello.rb
ファイルで、片側に「hello mundo」、もう片側に「hola world」があるチャンクのコンフリクトを見た場合、それを「hola mundo」に解決するという意味です。
これで、解決済みとしてマークしてコミットできます。
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
「Recorded resolution for FILE」と表示されます。

さて、そのマージを取り消し、代わりに master
ブランチの上にリベースしてみましょう。リセットの解明で見たように、git reset
を使用してブランチを元に戻すことができます。
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
マージが元に戻されました。次に、トピックブランチをリベースしましょう。
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
これで、予想通り同じマージコンフリクトが発生しましたが、Resolved FILE using previous resolution
の行を見てください。ファイルを見ると、すでに解決されており、マージコンフリクトマーカーは含まれていません。
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
また、git diff
は、それがどのように自動的に再解決されたかを示します。
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end

git checkout
でコンフリクトしたファイルの状態を再作成することもできます。
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
高度なマージでこの例を見ました。ただし、今回は git rerere
を再度実行するだけで再解決してみましょう。
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
rerere
のキャッシュされた解決策を使用して、ファイルを自動的に再解決しました。これで、リベースを追加して完了することができます。
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
したがって、多くの再マージを行う場合、または大量のマージなしでトピックブランチを master
ブランチと同期させたい場合、または頻繁にリベースを行う場合は、rerere
を有効にして作業を少し楽にすることができます。