-
1. はじめに
- 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ツール
-
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 プラミングとポーセリン
- 10.2 Gitオブジェクト
- 10.3 Gitリファレンス
- 10.4 パックファイル
- 10.5 リフスペック
- 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 プラミングコマンド
7.10 Gitツール - Gitでのデバッグ
Gitでのデバッグ
Gitは主にバージョン管理のために利用されますが、ソースコードプロジェクトのデバッグに役立つコマンドもいくつか提供しています。Gitはほぼあらゆる種類のコンテンツを扱えるように設計されているため、これらのツールは非常に汎用的ですが、問題が発生した際にバグや原因の特定に役立つことがよくあります。
ファイルの注釈付け
コード内のバグを突き止め、それがいつ、なぜ導入されたのかを知りたい場合、ファイルの注釈付けは多くの場合、最良のツールとなります。これは、どのコミットがファイルの各行を最後に変更したかを示します。そのため、コード内のメソッドにバグがあることがわかった場合、git blame
を使ってファイルに注釈を付け、その行が導入された原因となったコミットを特定できます。
以下の例では、git blame
を使用して、トップレベルのLinuxカーネルのMakefile
内の行について、どのコミットとコミッターが担当したかを特定し、さらに-L
オプションを使用して、そのファイルの69行目から82行目までの注釈の出力を制限しています。
$ git blame -L 69,82 Makefile
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 69) ifeq ("$(origin V)", "command line")
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 70) KBUILD_VERBOSE = $(V)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ifndef KBUILD_VERBOSE
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) KBUILD_VERBOSE = 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 76) ifeq ($(KBUILD_VERBOSE),1)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 77) quiet =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 78) Q =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 79) else
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 80) quiet=quiet_
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 81) Q = @
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 82) endif
最初のフィールドは、その行を最後に変更したコミットのSHA-1の一部であることに注意してください。次の2つのフィールドは、そのコミットから抽出された値(作者名とそのコミットの作成日)であり、誰がいつその行を変更したかを簡単に確認できます。その後に、行番号とファイルの内容が続きます。また、^1da177e4c3f4
のようなコミット行にも注目してください。ここで^
プレフィックスは、リポジトリの最初のコミットで導入されて以来、変更されていない行を示します。これは少し混乱を招くかもしれません。というのも、GitがコミットのSHA-1を変更するために^
を使用する方法が少なくとも3つあることをこれまでに見てきたからです。しかし、ここではそのように解釈されます。
Gitのもう一つの優れた点は、ファイルの名前変更を明示的に追跡しないことです。スナップショットを記録し、後から暗黙的に何が名前変更されたかを判断しようとします。これの興味深い機能の1つは、あらゆる種類のコード移動も判別できることです。git blame
に-C
オプションを渡すと、Gitは注釈を付けているファイルを分析し、コードスニペットが他の場所からコピーされた場合、それが元々どこから来たのかを特定しようとします。例えば、GITServerHandler.m
というファイルを複数のファイルにリファクタリングしており、そのうちの1つがGITPackUpload.m
だとします。-C
オプションを使ってGITPackUpload.m
をblameすると、コードの各セクションが元々どこから来たのかを確認できます。
$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144) //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 145)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 146) NSString *parentSha;
ad11ac80 GITPackUpload.m (Scott 2009-03-24 147) GITCommit *commit = [g
ad11ac80 GITPackUpload.m (Scott 2009-03-24 148)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 149) //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 150)
56ef2caf GITServerHandler.m (Scott 2009-01-05 151) if(commit) {
56ef2caf GITServerHandler.m (Scott 2009-01-05 152) [refDict setOb
56ef2caf GITServerHandler.m (Scott 2009-01-05 153)
これは本当に便利です。通常、元のコミットとして表示されるのは、そのコードをコピーしたコミットです。なぜなら、そのファイルでその行を初めて触ったのがその時だからです。Gitは、たとえそれが別のファイルにあったとしても、その行を最初に書いた元のコミットを教えてくれます。
バイナリサーチ
ファイルの注釈付けは、問題の箇所を最初から知っている場合に役立ちます。何が壊れているのかわからず、コードが機能していた最後の状態から数十または数百のコミットがある場合、git bisect
に助けを求めることになるでしょう。bisect
コマンドは、コミット履歴に対してバイナリサーチを実行し、どのコミットが問題を導入したかを可能な限り迅速に特定するのに役立ちます。
あなたのコードのリリースを本番環境にプッシュしたばかりで、開発環境では発生していなかったことについてバグ報告を受けており、なぜコードがそのような動作をするのか想像もつかないとします。コードに戻ると、その問題を再現できることがわかりますが、何が問題なのかは特定できません。その問題を特定するためにコードをバイセクトできます。まずgit bisect start
を実行して開始し、次にgit bisect bad
を使って、現在いるコミットが壊れていることをシステムに伝えます。次に、git bisect good <good_commit>
を使って、最後に正常だった状態がいつだったかをbisectに伝えなければなりません。
$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] Error handling on repo
Gitは、最後に正常なコミット(v1.0)としてマークしたコミットと現在の壊れたバージョンとの間に約12のコミットがあることを特定し、その中間にあるコミットをチェックアウトしました。この時点で、テストを実行して、このコミットで問題が存在するかどうかを確認できます。もし問題が存在すれば、この中間コミットより前に導入されたことになります。存在しなければ、問題は中間コミットより後に導入されたことになります。ここでは問題がないことが判明し、git bisect good
と入力してGitにそれを伝え、作業を続けます。
$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] Secure this thing
次に、先ほどテストしたコミットと壊れたコミットの中間にある別のコミットに移動します。もう一度テストを実行すると、このコミットが壊れていることが判明するため、git bisect bad
でGitにそのことを伝えます。
$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] Drop exceptions table
このコミットは問題なく、これでGitは問題がどこで導入されたかを特定するために必要なすべての情報を持っています。最初の壊れたコミットのSHA-1を伝え、そのコミットのコミット情報と変更されたファイルの一部を表示することで、このバグを導入した可能性のある出来事を特定できるようになります。
$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date: Tue Jan 27 14:48:32 2009 -0800
Secure this thing
:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M config
完了したら、git bisect reset
を実行して、開始前のHEADの状態に戻すべきです。そうしないと、奇妙な状態になる可能性があります。
$ git bisect reset
これは、数分で何百ものコミットから導入されたバグをチェックできる強力なツールです。実際、プロジェクトが正常であれば0を返し、問題があれば非0を返すスクリプトがあれば、git bisect
を完全に自動化できます。まず、既知の壊れたコミットと正常なコミットを提供することで、バイセクトの範囲を再度伝えます。これを希望する場合は、bisect start
コマンドでそれらをリストアップし、既知の壊れたコミットを最初に、既知の正常なコミットを2番目にリストアップすることで実行できます。
$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
これにより、Gitが最初に壊れたコミットを見つけるまで、チェックアウトされた各コミットでtest-error.sh
が自動的に実行されます。また、make
やmake tests
など、自動テストを実行するものを実行することもできます。