web-dev-qa-db-fra.com

Fusion d'une branche d'une branche après que la première branche a été écrasée lors de la fusion vers le master

Voici un flux de travail que je traite couramment au travail.

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

À ce stade, la branche des fonctionnalités doit être examinée par mes collègues, mais je souhaite continuer à développer d'autres fonctionnalités qui dépendent de feature_branch. Donc pendant feature_branch est en cours de révision ...

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

Maintenant, j'apporte quelques modifications en réponse à la révision du code sur feature_branch

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

Maintenant, c'est là que nous avons des problèmes. Nous avons une politique de squash sur master, ce qui signifie que les branches de fonctionnalités fusionnées en master doivent être écrasées en un seul commit.

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

Tout est cool, sauf avec dependent_branch. Lorsque j'essaie de rebaser une branche dépendante sur master ou d'essayer d'y fusionner master, git est confus par l'historique réécrit/écrasé et marque fondamentalement chaque changement dans depedendent_branch comme un conflit. Il s'agit d'un PITA à traverser et à refaire ou à décontacter tous les changements dans dependent_branch. Y a-t-il une solution à cela? Parfois, je crée manuellement un patch et l'applique sur une nouvelle branche de master, mais s'il y a de vrais conflits avec cela, c'est encore pire à corriger.

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.

Des idées? Je sais que cela se produit à cause de l'histoire réécrite pendant le squash, mais c'est une exigence que je ne peux pas changer. Quelle est la meilleure solution/solution de contournement? Puis-je faire de la magie? Ou existe-t-il un moyen plus rapide de faire toutes les étapes de la création manuelle du diff?

69
Mike

Un peu pourquoi cela se produit:

Je laisserai O être "maître d'origine" et FB sera "nouveau maître", après la fusion d'une branche de fonctionnalité:

Dire feature_branch ressemble à:

O - A - B - C 

dependent_feature a quelques commits supplémentaires en plus:

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

Vous fusionnez votre branche de fonctionnalité d'origine dans Master et la réduisez, vous donnant:

O - FB

Maintenant, lorsque vous essayez de rebaser la branche dépendante, git va essayer de comprendre l'ancêtre commun entre ces branches. Alors qu'il à l'origine aurait été C, si vous n'aviez pas écrasé les commits, git trouve à la place O comme ancêtre commun. Par conséquent, git essaie de rejouer A, B et C qui sont déjà contenus dans FB, et vous allez avoir un tas de conflits.

Pour cette raison, vous ne pouvez pas vraiment compter sur une commande de rebase typique, et vous devez être plus explicite à ce sujet en fournissant le --onto paramètre:

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

Modifier le HEAD~3 paramètre si nécessaire pour vos branches, et vous ne devriez pas avoir à gérer de résolution de conflit redondante.

Une syntaxe alternative, si vous n'aimez pas spécifier les plages et que vous n'avez pas encore supprimé votre branche de fonctionnalité d'origine:

git rebase --onto master feature_branch dependent_feature

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

Dans ce cas particulier, il semble que vous "sachiez" que seulement le travail écrasé de la branche sur laquelle vous avez travaillé à l'origine a été mis en master.

Ainsi, vous pouvez fusionner avec plaisir en conservant vos modifications à chaque fois qu'il y a un conflit. Il y a une option pour cela:

git merge -Xours master

Voir https://git-scm.com/docs/git-rebase pour plus de détails plus de détails.

1
nha

Je suis profondément en désaccord avec la politique de "réduire chaque développement de fonctionnalités en une seule validation", mais c'est leur appel ...

Je garderais les branches telles quelles et créerais un commit purifié juste pour publication, dans une branche spéciale. Être en mesure de suivre le développement étape par étape est précieux, même si la direction n'y croit pas. Marquez les emplacements des courges par des balises dans les branches "réelles", vous pouvez également ajouter des balises entre les courges avec des messages pointant vers les vrais commits.

0
vonbrand