2010-12-14 8 views
16

La situation: En commençant par le maître à A j'ai ramifié et apporté quelques modifications à B puis fusionné cette branche en (C). Après avoir apporté quelques modifications supplémentaires, j'étais au D mais j'ai trouvé que j'avais besoin de déployer le code sans les changements survenus dans la branche. Si je ne l'ai pas fusionné, ça aurait été bien.Git: comment "annuler" une fusion

A_______C___D 
\ /
    \_B_/ 

Tout d'abord, je voudrais savoir ce que je aurais dû le faire d'ici à déployer le code comme si la fusion n'a jamais eu lieu. Remarque: aucun des fichiers modifiés dans la branche n'a été modifié dans le maître.

... En second lieu

Je ne l'ai pas eu le temps de trouver la meilleure méthode pour faire face à cela, donc je supprimé les fichiers que la branche ajoutée et revins manuellement quelques modifications apportées dans la branche puis commited le résultat pour le déploiement (F)

A_______C___D___F 
\ /
    \_B_/ 

Je veux être en mesure de continuer à développer la branche et de fusionner toutes les modifications du maître en elle pour le maintenir à jour, mais si je fais que les choses que je faisais pour créer F seront fusionnés et entraînera la suppression des fichiers et la restauration des modifications. Quelle est la meilleure façon de gérer cela?

Répondre

16

Vous pouvez utiliser rebase pour le faire en une seule étape:

git rebase --onto A C D 

Je viens de tester cela, avec des résultats appropriés:

$ edit test.txt 
$ git add . 
$ git commit -mA 
$ git checkout -b the_branch 
$ edit test.txt 
$ git commit -a -mB 
$ git checkout master 
$ git merge master the_branch --no-ff 
$ edit test.txt 
$ git commit -a -mD 

De là, vous avez la situation que vous avez décrite. Puis:

$ git rebase --onto <SHA1-for-A> <SHA1-for-C> master 

rebasage engage de C (exclu) à maîtriser, sur A. que je devais corriger certains conflits depuis que je modifié au même endroit en B et D, mais je pense que vous ne serez pas.

_D' 
/
/
A_______C___D 
\ /
    \_B_/ 

Doc à propos git rebase --onto, qui est plus ou moins votre situation: http://git-scm.com/docs/git-rebase


Si vous aviez:

A_______C___D___F 
\ /
    \_B_/ 

, vous avez maintenant:

_D'___F'_(master) 
/
/
A_______C___D___F 
\ /
    \_B_/(the_branch) 

De là, fusionner les changements de master dans la branche est facile. Rejeter le commit F' tout à fait.

$ git checkout master # if you were not here already 
$ git branch old_fix # if you want to be able to return to F' later 
$ git reset --hard <SHA1-to-D'> 

Après les commandes ci-dessus vous avez:

 (master) 
    /
    _D'___F'_(old_fix) 
/
/
A_______C___D___F 
\ /
    \_B_/(the_branch) 

Pour fusionner les mises à jour de maître en the_branch:

$ git checkout the_branch 
$ git merge master 

... et fixer les conflits.

+0

Génial, merci! Je vais l'utiliser à l'avenir (si être plus prudent avec mes fusions ne fonctionne pas). Voir la réponse de @ terminus pour ce que j'ai fait. Je pense que cela a pratiquement donné le même résultat que votre réponse. – Jake

6

La solution évidente est de réinitialiser à A, réappliquer tous les correctifs manuellement et résoudre les conflits (que vous n'aurez pas).

Sinon, vous pouvez juste git revert patch B mais cela va créer une nouvelle validation.

Bien que la réponse de Gauthier soit meilleure.

+0

Merci, Après avoir lu ceci, j'ai regardé dans les correctifs et a fini ici: http://www.gitready.com/intermediate/2009/03/04/pick-out-individual-commits.html Donc, j'ai embranché A et D et F, puis fusionné le résultat dans la branche d'origine pour le mettre à jour. – Jake

+0

Avez-vous vraiment choisi F? Je pensais que F était seulement pour inverser B et C, donc il n'avait rien à faire après C '? – Gauthier

+0

Désolé, maintenant je ne suis pas sûr. Peut-être que je l'ai fait, mais je n'en avais pas vraiment besoin. – Jake