web-dev-qa-db-ja.com

マスターにマージされたときに最初のブランチが押しつぶされた後のブランチのブランチのマージ

これが私が仕事でよく扱うワークフローです。

git checkout -b feature_branch
# Do some development
git add .
git commit
git Push Origin feature_branch

この時点で、機能ブランチは同僚によるレビューの対象ですが、feature_branchに依存する他の機能の開発を続けたいと思います。 feature_branchのレビュー中...

git checkout feature_branch
git checkout -b dependent_branch
# Do some more development
git add .
git commit

今、feature_branchのコードレビューに応じていくつか変更を加えます

git checkout feature_branch
# Do review fixes
git add .
git commit
git checkout dependent_branch
git merge feature_branch

ここで問題が発生します。マスターにスカッシュポリシーがあります。つまり、マスターにマージされた機能ブランチは、単一のコミットにスカッシュする必要があります。

git checkout feature_branch
git log # Look for hash at beginning of branch
git rebase -i  first_hash_of_branch # Squash feature_branch into a single commit
git merge master

dependent_branchを除いて、すべてがクールです。依存するブランチをマスターにリベースしようとするか、マスターをマスターにマージしようとすると、gitは書き直された/潰された履歴に混乱し、基本的にdepedendent_branchのすべての変更を競合としてマークします。基本的に、dependent_branchのすべての変更をやり直したり、矛盾を解消したりするのはPITAです。これに対する解決策はありますか?場合によっては、手動でパッチを作成してマスターの新しいブランチから適用することもありますが、それと実際の競合がある場合は、修正するのがさらに困難です。

git checkout dependent_branch
git diff > ~/Desktop/dependent_branch.diff
git checkout master
git checkout -b new_dependent_branch
patch -p1 < ~/Desktop/dependent_branch.diff
# Pray for a clean apply.

何か案は?これはスカッシュ中に履歴が書き直されたために発生することを知っていますが、それは私が変更できない要件です。最良の解決策/回避策は何ですか?私にできる魔法はありますか?または、手動で差分を作成することに関するすべての手順を実行するより速い方法はありますか?

69
Mike

なぜこれが起こるのかについて少し:

機能ブランチがマージされた後、Oを「元のマスター」にし、FBを「新しいマスター」にする:

feature_branchは次のようになります。

O - A - B - C 

dependent_featureには、さらにいくつかの追加のコミットがあります。

O - A - B - C - D - E - F

元の機能ブランチをマスターにマージし、それを押しつぶして、次のようにします。

O - FB

ここで、依存するブランチをリベースしようとすると、gitはそれらのブランチ間の共通の祖先を理解しようとします。 元々Cでしたが、コミットを抑制していなければ、代わりにgitがOを共通の祖先として見つけます。結果として、gitはAB、およびCを再生しようとしています。これらはすでに含まれていますFBにあり、たくさんの衝突が発生します。

このため、一般的なrebaseコマンドに実際に依存することはできません。--ontoパラメータを指定して、コマンドをより明確にする必要があります。

git rebase --onto master HEAD~3  # instruct git to replay only the last
                                 # 3 commits, D E and F, onto master.

ブランチの必要に応じてHEAD~3パラメータを変更します。冗長な競合解決に対処する必要はありません。

範囲を指定したくない場合や、元の機能ブランチをまだ削除していない場合の代替構文:

git rebase --onto master feature_branch dependent_feature

                                 # replay all commits, starting at feature_branch
                                 # exclusive, through dependent_feature inclusive 
                                 # onto master
79
joshtkling

この特定のケースでは、元々作業していたブランチの押しつぶされた作業のみがマスターに入れられたことを「知っている」ようです。

したがって、競合が発生するたびに変更を保持することで、楽しくマージできます。そのためのオプションがあります:

git merge -Xours master

詳細については https://git-scm.com/docs/git-rebase を参照してください。

1
nha

「すべての機能開発を1つのコミットにまとめる」というポリシーには心から反対しますが、それは彼らの呼びかけです...

私はブランチを現状のまま維持し、特別なブランチに公開のためにマッシュアップされたコミットを作成します。経営陣が信じていなくても、段階的に開発を追跡できることは価値があります。スカッシュの場所を「実際の」ブランチのタグでマークします。スカッシュの間にタグを追加して、実際のコミットを指すメッセージを追加することもできます。

0
vonbrand