1. ホーム
  2. git

[解決済み] なぜ git はデフォルトで fast-forward マージを行うのですか?

2022-03-15 03:28:34

質問

mercurialから来た私は、機能を整理するためにブランチを使用しています。 当然ながら、このワークフローも履歴で確認したいです。

私はgitを使って新しいプロジェクトを開始し、最初の機能を完成させました。その機能をマージするときに、git が fast-forward を使っていることに気づきました。つまり、可能であれば私の変更を直接 master ブランチに適用して、私のブランチのことは忘れてしまうということです。

そこで、未来に思いを馳せる。このプロジェクトで作業しているのは私一人です。もし私が git のデフォルトのアプローチ(fast-forward merging)を使用すると、私の履歴は巨大なひとつの master ブランチになります。 私が機能ごとに別のブランチを使用していたことは誰も知りません。なぜなら、最終的に私が持つのは巨大な master ブランチだけだからです。プロらしくないと思われないでしょうか?

この理屈だと、私は早送りマージはいらないし、なぜデフォルトなのかもわかりません。何がそんなにいいのでしょうか?

解決方法は?

早送りのマージは、短命のブランチでは意味がありますが、より多くの 複雑な歴史 早送りでないマージの方が歴史がわかりやすく、コミット群のリバートもしやすいかもしれません。

警告 : 非速送りにも副作用の可能性があります。ご検討ください。 https://sandofsky.com/blog/git-workflow.html のデフォルトのアプローチにするかどうか、慎重に検討してください。 master .


(以下 nvie.com , ヴィンセント・ドリーセン , post " Git の成功するブランチングモデル ")

完成した機能をdevelopに取り込む

完成した機能は、develop ブランチにマージして、次のリリースに追加することができます。

$ 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 フラグを使用すると、マージが早送りで実行できた場合でも、常に新しいコミットオブジェクトを作成するようになります。これにより、ある機能ブランチの過去の存在に関する情報が失われるのを防ぎ、その機能を追加したすべてのコミットをグループ化します。

ヤコブ・ナレブスキー また 記載事項 その コンフィグ merge.ff :

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


早送りはデフォルトだから。

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

しかし、ひとつのトピック/機能ブランチでのワークフローを繰り返すことが予想される場合 (たとえば、マージしてからこの機能ブランチに戻り、さらにいくつかのコミットを追加する)、機能ブランチのすべての中間コミットではなく、マージだけをメインブランチに含めると便利です。

この場合、最終的に このような設定ファイル :

[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が想定しているということです。妥当でしょうか?

Jefromiさんが回答しています。

ブランチの寿命は、ユーザーによって大きく異なると思います。経験豊富なユーザーであれば、短命のブランチが圧倒的に多い傾向にあるでしょうが。

私にとっては 短命なブランチとは、ある操作を容易にするために作るブランチのことです。 (リベース、おそらく、または迅速なパッチとテスト) そして、終わったらすぐに削除します。
つまり、それはおそらく フォーク元のトピックブランチに吸収されるはずです。 そして、そのトピックブランチは1つのブランチとしてマージされます。その機能を実装するための一連のコミットを作成するために私が内部で何をしたかは、誰も知る必要はないのです。

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

によって異なります。 開発ワークフロー :

  • リニアであれば、1つのブランチが意味を持つ。
  • 機能を分離して長期間作業し、マージを繰り返す必要がある場合は、複数のブランチが理にかなっています。

"をご覧ください。 どのような場合にブランチングが必要ですか? "です。

実は、Mercurial のブランチモデルを考えるとき、その核となるのは リポジトリごとのブランチ (を作成することができます(ただし 匿名ヘッド、ブックマーク、さらには名前付きブランチ )
参照 Git と Mercurial - Compare and Contrast" .

<ブロッククオート

Mercurialは、デフォルトで匿名の軽量コードラインを使用します。
Gitは、軽量な名前付きブランチを使用し、リモート・リポジトリのブランチの名前をリモート・トラッキング・ブランチの名前にマッピングするための射影マッピングを使用します。
Gitは、ブランチに名前を付けることを強制します(ただし、名前の付いていない単一のブランチは例外で、これは"" "と呼ばれる状況です)。 切り離されたHEAD しかし、これはトピックブランチワークフローのようなブランチを多用するワークフロー、つまり1つのリポジトリパラダイムに複数のブランチがある場合により効果的だと思います。