-
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ツール
- 7.1 リビジョン選択
- 7.2 インタラクティブステージング
- 7.3 スタッシュとクリーン
- 7.4 作業の署名
- 7.5 検索
- 7.6 履歴の書き換え
- 7.7 リセットの謎解き
- 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 内部コマンドと外部コマンド
- 10.2 Gitオブジェクト
- 10.3 Gitリファレンス
- 10.4 パックファイル
- 10.5 Refspec
- 10.6 転送プロトコル
- 10.7 メンテナンスとデータ復旧
- 10.8 環境変数
- 10.9 まとめ
-
付録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 まとめ
-
付録B. アプリケーションへのGitの埋め込み
- A2.1 コマンドラインGit
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
付録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はほぼあらゆる種類のコンテンツを処理するように設計されているため、これらのツールは非常に汎用的ですが、問題が発生したときにバグや原因を特定するのに役立つことがよくあります。
ファイルの注釈
コードのバグを発見し、いつ、なぜ導入されたのかを知りたい場合、ファイルの注釈は最適なツールの1つです。これは、ファイルの各行を最後に変更したコミットを表示します。そのため、コードのメソッドにバグがあることがわかった場合は、`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つの優れた点は、ファイルの名前変更を明示的に追跡しないことです。スナップショットを記録し、後で暗黙的に何が名前変更されたかを推測しようとします。これの興味深い機能の1つは、あらゆる種類のコードの移動も調べることができることです。`git blame`に`-C`を渡すと、Gitは注釈を付けているファイルを分析し、コードのスニペットが他の場所からコピーされた場合、その元の場所を特定しようとします。たとえば、`GITServerHandler.m`という名前のファイルを複数のファイル(その1つは`GITPackUpload.m`)にリファクタリングするとします。`-C`オプションを使用して`GITPackUpload.m`を非難することで、コードのセクションが元々どこから来たのかを確認できます。
$ 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>
を使用して、最後に正常だった状態をバイセクトに伝えなければなりません。
$ 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 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は問題が導入された場所を特定するために必要な情報を得ました。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
コマンドでそれらをリストし、最初に既知の異常なコミット、次に既知の正常なコミットをリストできます。
$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
これにより、Gitが最初の壊れたコミットを見つけるまで、チェックアウトされた各コミットでtest-error.sh
が自動的に実行されます。make
やmake tests
など、自動テストを実行するものが他にあれば、それを実行することもできます。