65

ときどき、git の特定のブランチが開始するコミットについて、または特定のブランチで特定のコミットが作成されているかどうかを尋ねられます。ブランチの終点は非常に明確です。そこにブランチ ラベルが置かれます。しかし - それはどこから始まったのですか?些細な答えは、そのブランチを作成したそのコミットについてです。しかし、その情報は、私が今知る限り、最初のコミット後に失われてしまったので、質問をしているのです。

分岐したコミットがわかっている限り、グラフを描いて明確にすることができます。

A - B - C - - - - J     [master]
     \
      D - E - F - G     [branch-A]
           \
            H - - I     [branch-B]

コミット時にブランチ B を作成したEので、それが「開始」です。私はそれをやったので、私はそれを知っています。しかし、他の人はそれを同じように認識できますか? 同じグラフを次のように描画できます。

A - B - C - - - - J     [master]
     \
      \       F - G     [branch-A]
       \     /
        D - E
             \
              H - I     [branch-B]

では、グラフを見てください。どのブランチが で始まり、どのブランチが で始まりましEBか? commitDは両方のブランチのメンバーですか、それともブランチ A とブランチ B のどちらに属するかを明確に判断できますか?

これはやや哲学的に聞こえますが、実際にはそうではありません。スーパーバイザーは、いつブランチが開始されたか (通常はタスクの開始を示します)、変更がどのブランチに属しているか (変更の目的を把握するため - その変更は作業に必要だったのか) を知りたがる場合があります。これらの質問に正しく答えるために、git が情報 (ツール、コマンド) または定義を提供しているかどうかを知りたいです。

4

8 に答える 8

10

おそらく、あなたは間違った質問をしています。IMO、特定のブランチにはすべてのファイルに対して行われたすべての変更が含まれているため (つまり、最初のコミット以降) 、ブランチの開始場所を尋ねるのは意味がありません。

一方、2 つの分岐がどこで分岐したかを尋ねることは、間違いなく有効な質問です。実際、これはまさにあなたが知りたいことのようです。つまり、単一のブランチに関する情報を知りたいわけではありません。代わりに、2 つのブランチの比較に関する情報が必要です。

少し調べたところ、特定のコミットとコミットの範囲を参照する方法の詳細を説明している gitrevisions の man ページが見つかりました。特に、

コミットから到達可能なコミットを除外するには、プレフィックス ^ 表記が使用されます。たとえば、^r1 r2 は、r2 から到達可能なコミットを意味しますが、r1 から到達可能なコミットは除外します。

このセット操作は頻繁に使用されるため、省略形があります。2 つのコミット r1 と r2 がある場合 (上記のリビジョンの指定で説明した構文に従って名前が付けられます)、^r1 r2 によって r1 から到達可能なコミットを除いて、r2 から到達可能なコミットを要求でき、r1 として記述できます。 .r2.

したがって、質問の例を使用して、からbranch-A分岐するmasterコミットを取得できます

git log master..branch-A
于 2013-07-10T22:24:40.810 に答える
6

いくつかのアーキテクチャの詳細

Git はリビジョンを一連のコミットとしてリポジトリに保存します。これらのコミットには、最後のコミット以降のファイルへの変更に関する情報へのリンクと、重要なことに、以前のコミットへのリンクが含まれています。大まかに言うと、ブランチのコミット履歴は、最新のリビジョンからリポジトリのルートまでさかのぼる単一リンク リストです。任意のコミットでのリポジトリの状態は、そのコミットがルートまでさかのぼるすべてのコミットと組み合わされたものです。

それで、頭は何ですか?そして枝とは?

HEAD は、現在アクティブなブランチの最新のコミットへの特別なポインターです。master 1を含む各ブランチは、その履歴の最新リビジョンへのポインターでもあります。

泥のように透明?Pro Git bookの画像を使用した例を見てみましょう。2

シンプルな Git ツリー

この図では、4 つのコミットを持つ比較的単純なリポジトリがあります。 98ca9根です。master と testing の 2 つのブランチがあります。master ブランチは commitf30abで、testing ブランチは87ab2です。現在マスター ブランチで作業しているため、HEAD はマスター ブランチを指しています。サンプル リポジトリのブランチの履歴は次のとおりです (最新のものから古いものへ)。

testing:  87ab2 -> f30ab -> 34ac2 -> 98ca9
 master:           f30ab -> 34ac2 -> 98ca9

このことから、2 つのブランチは から始まる同じであることがf30abわかります。したがって、testing はそのコミットでのブランチであるとも言えます。

Pro Git の本にはさらに詳しい説明があり、一読の価値があります。

これで対処できます--

特定の質問

得られた図を空想すると、次のようになります。

お茶を飲む小指のようなファンシー。

コミット D は両方のブランチのメンバーですか、それともブランチ A とブランチ B のどちらに属しているかを明確に判断できますか?

今わかっていることから、コミット D は、ブランチ ポインターからルートに至る両方のチェーンのメンバーであることがわかります。したがって、D は両方のブランチのメンバーであると言えます。

E で始まったブランチと、B で始まったブランチはどれ?

ブランチ A とブランチ B の両方が B のマスター ブランチから始まり、E で互いに分岐します。Git 自体は、どのブランチが E を所有しているかを区別しません。そのコアでは、ブランチは最新のものから最新のものまでのコミットのチェーンです。最も古いものがルートになります。


1豆知識: master ブランチは単なる普通のブランチです。他の支店と変わりません。

2 Pro Git ブックは、Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License でライセンスされています。

于 2015-10-17T00:59:20.090 に答える
6

哲学的な観点からすると、ブランチの歴史の問題は、グローバルな意味で答えることはできません。ただし、 はその特定のリポジトリ内reflogの各ブランチの履歴を追跡します。

したがって、誰もがプッシュする単一の中央リポジトリがある場合は、それを使用しreflogてこの情報を追跡できます (詳細については、この質問を参照してください)。まず、その中央リポジトリで、reflog が記録され、消去されないようにします。

$ git config core.logAllRefUpdates true
$ git config gc.reflogExpire never

次に、実行git reflog <branchname>してブランチの履歴を調べることができます。

テスト リポジトリに数回プッシュして、サンプル コミット グラフを再現しました。今、私はこの種のことを行うことができます:

$ git log --graph --all --oneline --decorate
* 64c393b (branch-b) commit I
* feebd2f commit H
| * 3b9dbb6 (branch-a) commit G
| * 18835df commit F
|/  
* d3840ca commit E
* b25fd0b commit D
| * 8648b54 (master) commit J
| * 676e263 commit C
|/  
* 17af0d2 commit B
* bdbfd6a commit A

$ git reflog --date=local master branch-a branch-b
64c393b branch-b@{Sun Oct 11 21:45:03 2015}: push
3b9dbb6 branch-a@{Sun Oct 11 21:45:17 2015}: push
18835df branch-a@{Sun Oct 11 21:43:32 2015}: push
8648b54 master@{Sun Oct 11 21:42:09 2015}: push
17af0d2 master@{Sun Oct 11 21:41:29 2015}: push
bdbfd6a master@{Sun Oct 11 21:40:58 2015}: push

したがって、私の例では、branch-a最初に存在したときは commit を指していFて、中央サーバーへの 2 回目のプッシュによって commit に移動したことがわかりますG。最初に存在したときbranch-bは commit を指していましたがI、まだ更新されていません。

注意事項

これは、中央リポジトリにプッシュされたときの履歴のみを示しています。たとえば、同僚がbranch-AcommitAで開始したが、プッシュする前に commitにリベースしたB場合、その情報は中央リポジトリの reflog に反映されません。

これはまた、分岐が始まった場所の決定的な記録も提供しません。Dどのブランチがコミットを「所有」しておりE、最初に master からフォークされたものかは、はっきりとは言えません。それらは で作成されて で取得されましたbranch-abranch-b、それともその逆ですか?

両方のブランチは、最初にそれらのコミットを含む中央リポジトリにreflog表示され、中央リポジトリに最初に表示されたブランチがわかりました。ただし、これらのコミットは、 などを介して、いくつかのエンドユーザー リポジトリ間で「渡された」可能性がありますformat-patch。そのため、どのブランチ ポインターがそれらを最初に中央サーバーに運ぶ役割を果たしたかはわかっていても、それらの最終的な発信元はわかりません。

于 2015-10-12T02:02:48.733 に答える