Comment déplacer certains commits pour qu'ils soient basés sur une autre branche dans git?

381

La situation:

  • le maître est à X
  • quickfix1 est à X + 2 commits

Tel que:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Ensuite, j'ai commencé à travailler sur quickfix2, mais par accident, j'ai pris quickfix1 comme branche source à copier, pas le maître. Maintenant, quickfix2 est à X + 2 validations + 2 validations pertinentes.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Maintenant, je veux avoir une branche avec quickfix2, mais sans les 2 commits qui appartiennent à quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

J'ai essayé de créer un correctif à partir d'une certaine révision dans quickfix2, mais le correctif ne conserve pas l'historique des validations. Existe-t-il un moyen de sauvegarder mon historique de commit, mais d'avoir une branche sans changements dans quickfix1?

Alex Yarmula
la source
8
@Kevin Cette question ne concerne que le déplacement des validations d'une branche vers une autre, celle-ci a la condition supplémentaire de ne pas inclure les validations quickfix1. (Notez également la différence dans les réponses.)
Scott Weldon

Réponses:

372

Il s'agit d'un cas classique de rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Vous devriez donc passer de

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

à:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Il est préférable de le faire sur un arbre de travail propre.
Voirgit config --global rebase.autostash true , surtout après Git 2.10 .

VonC
la source
24
Sachez que ces étapes modifieront l'historique de quickfix2, donc si vous avez déjà partagé la branche, utilisez plutôt la sélection de cerises (voir les réponses suivantes).
Max Chernyak
Juste pour les enregistrements: avec journal juste le glisser de SmartGit q2aONTO Xet sélectionnez Rebase 2 commits à partir des options de la boîte de dialogue se produire.
Thomas S.
1
@ThomasS. Intéressant. C'est une belle implémentation graphique d'un git rebase --onto.
VonC
1
Je dois admettre que je fais des choses idiotes comme m'engager sur la mauvaise branche plus souvent que je ne le devrais vraiment, l'interface graphique de la vue du journal SmartGit m'a sauvé tellement de fois avec la même situation.
WORMSS
1
@Cosine a accepté. J'ai édité ma réponse pour ajouter la référence à la rebase.autostashconfiguration: cela évitera toute perte de travail en cours dans l'arborescence de travail lors d'un rebase.
VonC
155

Vous pouvez utiliser git cherry-pickpour sélectionner simplement le commit sur lequel vous souhaitez copier.

La meilleure façon est probablement de créer la branche à partir du maître, puis dans cette branche, utilisez git cherry-pickles 2 validations de quickfix2 que vous souhaitez.

DJ.
la source
C'est également la meilleure option si vous souhaitez déplacer un seul commit. Merci.
Alex
142

La chose la plus simple que vous puissiez faire est de choisir une gamme. Il fait la même chose que le rebase --ontomais est plus facile pour les yeux :)

git cherry-pick quickfix1..quickfix2
Christoph
la source
6
aussi, il ne perd pas les commits d'origine, IIUC, semble donc préférable pour les "play-it-safes" comme moi;) ou rebase --ontoconserve- t-il également les modifications d'origine?
akavel
6
à la fois rebaseet cherry-pickvous donner de nouvelles clés SHA. En effet, chaque commit est un instantané unique du référentiel.
Christoph du
6
Ce que @akavel voulait dire, c'est que cherry-pick conservera les commits originaux dans leur branche, ce qui est vrai
Mr_and_Mrs_D
4
Pour tout ce que ça vaut, j'ai essayé cherry-pickune gamme comme dans cette réponse et ça a confondu mon repo. J'ai dû faire des cherry-picks pour chaque commit. (Et peut-être que cela va sans dire, mais au cas où quelqu'un aurait du mal, vous devez le faire cherry-pickdans l'ordre chronologique dans lequel vos commits ont été appliqués.)
carmenism
3
git checkoutest crucial ici. quelle est votre TÊTE :)?
Sławomir Lenart
28

Je crois que c'est:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
la source
3
cherry-pickfonctionne avec les hachages de validation, donc, si vous voulez simplement récupérer une validation de quelque part et la placer ailleurs, c'est la voie à suivre. Assurez-vous simplement de faire checkout <branch>d'abord la bonne branche.
John Leidegren
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Autres commandes plus utiles ici avec explication: Git Guide

Gaufre
la source