なぜgitコミットには作成されたブランチの名前が含まれないのですか?


20

機能ブランチを使用してチームでgitを操作するとき、歴史上のブランチ構造を理解するのが難しいことがよくあります。

例:

機能ブランチfeature / make-coffeeがあり、機能のブランチと並行してmasterでバグ修正が続けられたとしましょう。

履歴は次のようになります。

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

問題

一見したところ、どちら側が機能ブランチであるかを判断するのは難しいと思います。私は通常、どちらがどちらであるかを知るために、両側のいくつかのコメントを閲覧する必要があります。これは、複数の機能ブランチが並行して存在する場合(特に密接に関連する機能のためのものである場合)、または機能ブランチとマスターの間で両方向にマージされた場合、より複雑になります。

対照的に、Subversionでは、ブランチ名が履歴の一部であるため、これは非常に簡単です。したがって、「feature / make-coffee」でコミットが最初に行われたことがすぐにわかります。

Git 、コミットを作成するときに(作成者、日付などとともに)コミットメタデータに現在のブランチの名前を含めることで、これを簡単にします。ただし、gitはこれを行いません。

これが行われない根本的な理由はありますか?それとも、誰もこの機能を望んでいないということですか?後者の場合、名前を見ずに歴史的な枝の目的を理解する他の方法はありますか?


1
関連質問:コミットがどのブランチから来たかを見つける。これは、gitが明示的に記録しないにもかかわらず、この情報を見つける方法に関するものです。
sleske

1
自己への注意:興味深いことに、Mercurialでは、コミットにブランチ名含まれてます。そのため、Mercurial開発者はgit開発者とは異なる設計上の決定を下したようです。たとえば、felipec.wordpress.com / 2012/05/26 /…を参照してください。
sleske

回答:


14

おそらく、ブランチ名は1つのリポジトリ内でのみ意味があるためです。私がmake-coffeeチームにいて、ゲートキーパーを介してすべての変更を送信すると、私のmasterブランチはゲートキーパーのmake-coffee-guiブランチに引っ張られ、中央のブランチにマージされるブランチmake-coffee-backendにリベースする前にmake-coffeeブランチとマージされmasterます。

1つのリポジトリ内であっても、ワークフローの進化に応じてブランチ名を変更できます。 たとえば、master後で呼び出されるように変更されるdevelopment場合があります。

CodeGnomeが示唆したように、gitは、必要でない場合はデータに何かを焼き付けないという強力な設計哲学を持っています。ユーザーは使用中の選択肢に期待されているgit logし、git diff事後に自分好みにデータを出力します。自分に合った形式が見つかるまで試してみることをお勧めします。 git log --first-parentたとえば、マージされるブランチからのコミットは表示されません。


2
ただし、最初の親は通常間違っていることに注意してください。通常、作業中のものにマスターを引き込み、自分の作業を最初の親にし、2番目の作業をマスターにします。
ジャン・ヒューデック

1
@JanHudec:実際には、これは依存します:-)。作業を行う人がそれをマージする場合、はい。後で、おそらくレビュー後にマージが発生する場合、レビューアがマスターをチェックアウトし、機能ブランチをマスターにマージし、テストしてプッシュする可能性が高くなります。
sleske 14年

5

ブランチ履歴を追跡 --no-ff

Gitでは、コミットには祖先がありますが、「ブランチ」は実際には開発ラインの現在のヘッドにすぎません。つまり、コミットはある時点での作業ツリーのスナップショットであり、一度に任意の数のブランチに属することができます。これは、他のDVCSと比較した場合にGit分岐を非常に軽量にするものの一部です。

Gitのコミットにはブランチ情報は含まれません。Gitの履歴には必要ないためです。ただし、早送りではないマージでは、マージされたブランチに関する追加情報が確実に伝達されます。常に--no-ffフラグをマージに渡すことで、履歴にこの情報が含まれていることを確認できます。git-merge(1)のコメント:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

通常、これによりに類似したマージメッセージが作成されるため、Merge branch 'foo'通常、次のような行で「祖先ブランチ」に関する情報を見つけることができます。

$ git log --regexp-ignore-case --grep 'merge branch'

感謝しますが、それは(ほとんど)私の質問に答えません。元のブランチを見つける他の方法はありませんが、通常のメタデータとして情報が含まれていない理由を尋ねているわけではありません。これは設計上の問題です。
sleske

1
@sleske私の答えはレスポンシブだと思います。Gitの履歴には必要ないので、Gitはそれを追跡しません。それ以上に根本的なものになるとは思いません。ソースの詳細を確認する必要がありますが、履歴は現在のブランチの先端から事実上逆算されます。ブランチをファーストクラスのオブジェクトとして扱う他のDVCSといつでも比較でき、その設計哲学が好きかどうかを確認できます。YMMV。
CodeGnome

1
最後の1つであるべきですgit log --merges
ダン

3

最も簡単な答えは、ブランチの名前は短命であるということです。たとえば、ブランチの名前を変更した場合(git branch -m <oldname> <newname>)?そのブランチに対するすべてのコミットはどうなりますか?または、2人の人々が異なるローカルリポジトリに同じ名前のブランチを持っている場合はどうなりますか?

gitで意味を持つ唯一のものは、コミット自体のチェックサムです。これは追跡の基本単位です。

情報はそこにあります、あなたはそれを求めていないだけで、正確にそこにありません。

Gitは各ブランチのヘッドのチェックサムをに保存します.git/refs/heads。例えば:

... /。git / refs / heads $ lsテスト 
-rw-rw-r-- 1 michealt michealt 41 Sep 30 11:50テスト
... /。git / refs / heads $ catテスト 
87111111111111111111111111111111111111111d4

(はい、私はgitチェックサムを壊していますが、特別ではありませんが、それらはプライベートリポジトリであり、誤って何かを漏らす必要がない瞬間を探しています)。

これを見て、これを親、または親親または親親として持つすべてのコミットを追跡することにより、特定のコミットがどのブランチにあるかを調べることができます。レンダリングするための大きなグラフです。

特にブランチの名前(上記のように変更可能)がコミット自体のどこにあるかを保存することは、それを助けないコミットの余分なオーバーヘッドです。コミットの親を保存します。

適切なフラグを指定してgit logコマンドを実行すると、ブランチを確認できます。

git log --branches --source --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

そのために必要なものを選択する多くの異なる方法があります-gitログのドキュメントを見てください- -allセクションとそれに続くいくつかのオプション。

* 87111111111111111111111111111111111111111d4テストブランチ 'test1'をテストにマージ
| \  
| * 42111111111111111111111111111111111111e8 test1更新:ものを追加
* | dd11111111111111111111111111111111111111159 testブランチ「test3」をテストにマージ
| \ \  

その 'test'、 'test1'、および 'test2'は、これらがコミットされたブランチです。

gitログのドキュメントは膨大であり、必要ものをほぼすべて入手できることに注意してください。


3

なぜgitコミットに作成されたブランチの名前が含まれていないのですか?

設計上の決定です。その情報が必要な場合は、prepare-commit-msgまたはcommit-msgフックを追加して、単一のリポジトリでそれを実施できます。

BitKeeper災害の後、Linus TorvaldsはLinuxカーネル開発プロセスに合わせてgitを開発しました。そこで、パッチが受け入れられるまで、それは修正され、編集され、数回(すべてメールで)洗練され、サインオフ(=コミットの編集)、チェリーピック、中liの枝にさまよい、しばしばリベースされ、より多くの編集、チェリー-Linusによって最終的にアップストリームにマージされるまで、ピックします。

このようなワークフローでは、コミットの特定の起源がない場合があり、gitは配布されているため、重要でないプライベートランダムリポジトリの一時的なデバッグブランチでコミットが作成されることがよくあります。

たぶんその設計決定は偶然に起こっただけかもしれませんが、Linuxカーネルの開発プロセスとまったく同じです。


2

Gitでは、機能ブランチがマージされると、「コーヒーを作る」などのコミットが両方のブランチの一部と見なされるためです。次のことを確認するコマンドもあります。

% git branch --contains @
  feature/make-coffee
  master

また、支社は安価で、ローカルで、空気が詰まっています。サーバーから簡単に追加、削除、名前変更、プッシュ、削除できます。

Gitはすべてを実行できるという原則に従っているため、リモートサーバーからブランチを簡単に削除でき、履歴を簡単に書き換えることができます。

私が「マスター」ブランチにいて、「コーヒーを作る」と「ミルクと砂糖を追加する」という2つのコミットを行ったとしましょう。そのために新しいブランチを使用することにし、「マスター」を「元の」にリセットします/マスター'。問題ではありません。すべての歴史はまだきれいです。「コーヒーを作る」と「ミルクと砂糖を追加する」はマスターの一部ではなく、機能/コーヒーを作るだけです。

Mercurialは反対です。物事を変えたくないのです。ブランチは永続的であり、書き換え履歴は眉をひそめます。サーバーからブランチを削除することはできません。

要するに、Gitはあなたがすべてをできるようにし、Mercurialは物事を簡単にしたい(そして、あなたがやりたいことをさせるのを本当に難しくします)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.