web-dev-qa-db-ja.com

なぜgit commitには、作成されたブランチの名前が含まれていないのですか?

機能ブランチを使用するチームで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」でコミットされたことがすぐにわかります。

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

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

20
sleske

おそらくブランチ名は1つのリポジトリ内でのみ意味があるためです。 _make-coffee_チームに所属していて、すべての変更をゲートキーパー経由で送信すると、私のmasterブランチがゲートキーパーの_make-coffee-gui_ブランチにプルされ、_make-coffee-backend_ブランチ。中央のmasterブランチにマージされる_make-coffee_ブランチにリベースする前。

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

CodeGnomeが言及したように、gitにはstrong設計哲学があり、それが必要ない場合はデータに何かを焼き付けません。ユーザーは、_git log_および_git diff_のオプションを使用して、事後にデータを自分の好みに出力することが求められます。自分に合ったフォーマットが見つかるまで試してみることをお勧めします。たとえば、_git log --first-parent_は、マージされるブランチからのコミットを表示しません。

14
Karl Bielefeldt

--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'
5
CodeGnome

なぜgit commitには、作成されたブランチの名前が含まれていないのですか?

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

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

このようなワークフローでは、コミットの特定のオリジンはなく、gitが配布されているため、多くの場合、面白いブランチ名を持つ重要でないプライベートランダムリポジトリの一時的なデバッグブランチでコミットが作成されるだけです。

たぶんその設計上の決定は偶然に起こったかもしれませんが、それはLinuxカーネルの開発プロセスと完全に一致します。

3
villekulla

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

Gitで意味を持つ唯一のものは、コミット自体のチェックサムです。これがトラッキングの基本単位です。

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

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

 ... /。git/refs/heads $ ls test 
-rw-rw-r-- 1 michealt michealt 41 Sep 30 11:50 test 
 .../.git/refs/heads $ cat test 
 87111111111111111111111111111111111111d4 

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

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

具体的にはブランチの名前(上記のように変更される可能性があります)がコミット自体のどこに格納されているかは、コミットに余分なオーバーヘッドがかかり、役に立ちません。コミットの親とその善を格納します。

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

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

そのために必要なものを選択するには、さまざまな方法があります- git log のドキュメント--allセクションとそれに続くいくつかのオプションをご覧ください。

 * 87111111111111111111111111111111111111d4 testブランチ 'test1'をテストにマージします
 |\
 | * 42111111111111111111111111111111111111e8 test1更新:スタッフを追加
 * | dd11111111111111111111111111111111111159 testマージブランチ 'test3'をtest 
 |\\ 
にマージします

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

Gitログのドキュメントはhugeであり、ほとんどすべての情報を得ることができることに注意してください。

3
user40980

Gitでは、「make coffee」のようなコミットは、機能ブランチがマージされるときにbothブランチの一部と見なされるためです。それをチェックするコマンドさえあります:

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

また、ブランチは安価で、ローカルで、Etherealです。それらはサーバーから簡単に追加、削除、名前変更、プッシュ、および削除できます。

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

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

Mercurialはその逆です。物事を変えたいとは思わない。ブランチは永続的であり、リライト履歴は不快です。サーバーからブランチを削除することはできません。

つまり、Gitはあらゆることを可能にし、Mercurialは物事を簡単にしたいと考えています(そして、自分がやりたいことを実行させることを本当に難しくしています)。

2
FelipeC