web-dev-qa-db-ja.com

Gitがデフォルトで早送りマージを実行するのはなぜですか?

Mercurialから来たので、ブランチを使って機能を整理しています。当然、私もこのワークフローを私の歴史の中で見たいと思います。

私はgitを使って新しいプロジェクトを始め、最初の機能を完成させました。機能をマージするとき、私はgitが早送りを使うことに気付きました。すなわち、可能ならば私の変更を直接マスターブランチに適用し、私のブランチを忘れます。

だから将来を考えると:私はこのプロジェクトに取り組んでいるのは私だけです。もし私がgitのデフォルトのアプローチ(早送りマージ)を使用するなら、私の歴史は一つの巨大なマスターブランチになるでしょう。結局のところ、私はその巨大なマスターブランチだけを持つことになるので、私がすべての機能に別々のブランチを使ったことを誰も知っていません。それは非専門的に見えませんか?

この推論では、早送りマージはしたくないし、なぜそれがデフォルトなのかわかりません。何がそんなに良いの?

628
Florian Pilz

早送りマージは短命ブランチには意味がありますが、より多くの 複雑な履歴 では、非早送りマージは履歴を理解しやすくし、コミットのグループを元に戻しやすくします。

警告:非早送りには潜在的な副作用もあります。 https://sandofsky.com/blog/git-workflow.html を確認し、二分法または非難を破る「チェックポイントコミット」で「no-ff」を避け、それが必要かどうかを慎重に検討してくださいmasterのデフォルトのアプローチになります。

alt text
(from nvie.comVincent Driessen 、post " 成功した​​Git分岐モデル ")

開発に完成した機能を組み込む

完成した機能は、次のリリースに追加するために開発ブランチにマージされる場合があります。

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git Push Origin develop

--no-ffフラグを使用すると、マージが早送りで実行できる場合でも、マージは常に新しいコミットオブジェクトを作成します。これにより、機能ブランチの過去の存在に関する情報が失われることを回避し、機能を一緒に追加したすべてのコミットをグループ化します。

JakubNarębski also mentions the configmerge.ff

デフォルトでは、Gitは現在のコミットの子孫であるコミットをマージするときに追加のマージコミットを作成しません。代わりに、現在のブランチの先端は早送りされます。
falseに設定すると、この変数はそのような場合に追加のマージコミットを作成するようにGitに指示します(コマンドラインから--no-ffオプションを指定するのと同じです)。
only」に設定すると、このような早送りマージのみが許可されます(コマンドラインから--ff-onlyオプションを指定するのと同じです)。


早送りがデフォルトです:

  • 短命ブランチはGitで非常に簡単に作成して使用できます
  • 短命のブランチは、多くの場合、そのブランチ内で自由に再編成できる多くのコミットを分離します
  • これらのコミットは、実際にはメインブランチの一部です。再編成されると、メインブランチはそれらを含めるように早送りされます。

ただし、1つのトピック/機能ブランチで反復ワークフローが予想される場合(つまり、マージしてからこの機能ブランチに戻り、さらにコミットを追加する場合)、マージのみをメインブランチに含めるよりも便利です機能ブランチのすべての中間コミット。

この場合、 この種類の設定ファイル を設定することになります:

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

OPはコメントに追加します。

[短命]ブランチの早送りにはある程度の意味がありますが、これをデフォルトのアクションにすると、gitが... [短命]ブランチを持っていると仮定することになります。合理的ですか?

ジェフロミの答え:

ブランチの存続期間はユーザーごとに大きく異なると思います。ただし、経験豊富なユーザーの間では、ブランチの寿命がはるかに長くなる傾向があります。

私にとって、短命ブランチは、特定の操作を簡単にするために作成するブランチです(リベース、可能性、または迅速なパッチ適用とテスト) 、完了したらすぐに削除します。
つまり、分岐したトピックブランチにが吸収される可能性があり、トピックブランチは1つのブランチとしてマージされます。その特定の機能を実装する一連のコミットを作成するために、私が社内で行ったことを誰も知る必要はありません。

より一般的には、私は追加します:

それは本当にあなたの 開発ワークフロー に依存します:

  • 線形の場合、1つのブランチが意味を持ちます。
  • 機能を分離して長期間にわたって作業し、それらを繰り返しマージする必要がある場合は、いくつかのブランチが有効です。

いつ分岐する必要がありますか? "

実際、Mercurialブランチモデルを検討する場合、そのコアは oneリポジトリごとのブランチ (作成できますが 匿名ヘッド、ブックマーク、さらには名前付きブランチ
「GitとMercurial-比較とコントラスト」 を参照してください。

デフォルトでは、Mercurialは匿名の軽量コードラインを使用します。用語は「ヘッド」と呼ばれます。
Gitは軽量の名前付きブランチを使用し、リモートリポジトリ内のブランチの名前をリモートトラッキングブランチの名前にマッピングするための注入マッピングを備えています。
Gitはブランチに名前を「強制」します(1つの名前のないブランチは例外です。これは「 detached HEAD 」と呼ばれる状況です)。トピックブランチワークフローなどのブランチ中心のワークフローでは、1つのリポジトリパラダイム内の複数のブランチを意味します。

709
VonC

VonC非常に包括的な答え を少し拡張してみましょう。


第一に、私がそれを正しく覚えていれば、デフォルトでGitが早送りの場合にマージコミットを作成しないという事実は考慮から来ていますミューチュアルプルはこれらの2つのリポジトリを同期するために使用されます(「Gitを含む、ほとんどのユーザーのドキュメントで最初の例として見つけることができるワークフロー)。ユーザーズマニュアル」および「例によるバージョン管理」を参照してください。この場合、完全に実現されたブランチをマージするためにpullを使うのではなく、他の仕事についていくためにそれを使います。同期を実行しても保存され、将来的に保存されるようになったときに、一時的で重要ではない事実を持ちたくありません。

フィーチャブランチの有用性と単一のリポジトリに複数のブランチを持つことの有用性は、優れたマージサポートを備えたVCSのより広範な使用、およびさまざまなマージベースのワークフローの試行によって後になって初めて現れました。そのため、例えばMercurial:The Definitive Guideの古いリビジョンに見られるように、Mercurialは元々リポジトリごとに1つのブランチ(リモートブランチを追跡するための匿名のヒント)しかサポートしていませんでした。


次に、ベストプラクティスfeature branchesの場合、つまりその機能ブランチはすべて安定版から始めるべきです(マージする機能ブランチを選択することで、どの機能を選択して含めるかを選択することができるようにするには、を使用します。通常、早送りはしていませんこの問題は議論の余地があります...最初のブランチをマージするときには、真のマージを作成して早送りしないように注意する必要があります(シングルコミットの変更を直接 'master'に設定しないと仮定します)。それ以降の他のすべてのマージは、もちろん早送りではありません。

HTH

41
Jakub Narębski