Je voudrais déplacer les dernières validations que je me suis engagé à maîtriser dans une nouvelle branche et les reprendre avant que ces validations ne soient effectuées. Malheureusement, mon Git-fu n'est pas encore assez fort, une aide?
Ie comment puis-je aller de là
master A - B - C - D - E
pour ça?
newbranch C - D - E
/
master A - B
git
git-branch
branching-and-merging
Mark A. Nicolosi
la source
la source
Réponses:
Passer à une succursale existante
Si vous souhaitez déplacer vos commits vers une branche existante , cela ressemblera à ceci:
L'
--keep
option conserve toutes les modifications non validées que vous pourriez avoir dans des fichiers non liés, ou annule si ces modifications doivent être écrasées - de la même manière que ce qui segit checkout
produit. S'il échoue,git stash
vos modifications et réessayez, ou utilisez--hard
pour perdre les modifications (même à partir de fichiers qui n'ont pas changé entre les validations!)Déménagement dans une nouvelle succursale
Cette méthode fonctionne en créant une nouvelle branche avec la première commande (
git branch newbranch
) mais sans y basculer. Ensuite, nous restaurons la branche actuelle (maître) et passons à la nouvelle branche pour continuer à travailler.Mais assurez-vous du nombre de commits pour revenir. Alternativement, au lieu de
HEAD~3
, vous pouvez simplement fournir le hachage du commit (ou la référence commeorigin/master
) que vous souhaitez revenir, par exemple:AVERTISSEMENT: avec Git version 2.0 et versions ultérieures, si vous placez plus tard
git rebase
la nouvelle branche sur la branche d'origine (master
), vous aurez peut-être besoin d'une--no-fork-point
option explicite lors du rebase pour éviter de perdre les validations que vous avez déplacées de la branche principale. Labranch.autosetuprebase always
mise en place rend cela plus probable. Voir la réponse de John Mellor pour plus de détails.la source
Pour ceux qui se demandent pourquoi cela fonctionne (comme je l'étais au début):
Vous voulez revenir à C et déplacer D et E vers la nouvelle branche. Voici à quoi cela ressemble au début:
Après
git branch newBranch
:Après
git reset --hard HEAD~2
:Puisqu'une branche n'est qu'un pointeur, master a indiqué le dernier commit. Lorsque vous avez créé newBranch , vous avez simplement créé un nouveau pointeur vers le dernier commit. Ensuite , en utilisant
git reset
vous avez déplacé le maître Backpointer deux commits. Mais comme vous n'avez pas déplacé newBranch , cela indique toujours le commit qu'il a fait à l'origine.la source
git push origin master --force
pour que la modification apparaisse dans le référentiel principal.git rebase
, les 3 commits seront supprimés en silencenewbranch
. Voir ma réponse pour plus de détails et des alternatives plus sûres.origin/master
n'apparaît pas dans le diagramme ci-dessus. Si vous poussiezorigin/master
puis apportiez les modifications ci-dessus, bien sûr, les choses deviendraient drôles. Mais c'est un problème "Docteur, ça fait mal quand je fais ça". Et c'est hors de portée de ce que la question d'origine demandait. Je vous suggère d'écrire votre propre question pour explorer votre scénario au lieu de détourner celui-ci.git branch -t newbranch
". Revenez en arrière et relisez les réponses. Personne n'a suggéré de faire ça.newbranch
être basés sur leurmaster
branche locale existante . Après avoir effectué la réponse acceptée, lorsque l'utilisateur se déplace à courirgit rebase
dansnewbranch
, git leur rappellera qu'ils ont oublié de mettre la branche en amont, donc ils vont courirgit branch --set-upstream-to=master
ensuitegit rebase
et ont le même problème. Ils peuvent tout aussi bien utilisergit branch -t newbranch
en premier lieu.En général...
La méthode exposée par sykora est la meilleure option dans ce cas. Mais parfois, ce n'est pas le plus simple et ce n'est pas une méthode générale. Pour une méthode générale, utilisez git cherry-pick :
Pour réaliser ce que OP souhaite, c'est un processus en 2 étapes:
Étape 1 - Notez les validations du master que vous souhaitez sur un
newbranch
Exécuter
Notez les hachages (par exemple 3) des commits que vous souhaitez
newbranch
. Ici, je vais utiliser:C commit:
9aa1233
D commit:
453ac3d
E commit:
612ecb3
Étape 2 - Mettez-les sur le
newbranch
OU (sur Git 1.7.2+, utilisez des plages)
git cherry-pick applique ces trois commits à newbranch.
la source
Encore une autre façon de le faire, en utilisant seulement 2 commandes. Maintient également intact votre arbre de travail actuel.
Ancienne version - avant d'en savoir plus
git branch -f
Être capable de le
push
faire.
est une bonne astuce à savoir.la source
git branch -f
ici?.
est le directeur actuel. git peut pousser vers REMOTES ou GIT URLs.path to local directory
est prise en charge la syntaxe des URL Git. Voir la section URL GIT dansgit help clone
.La plupart des réponses précédentes sont dangereusement erronées!
Ne faites pas cela:
Comme la prochaine fois que vous exécuterez
git rebase
(ougit pull --rebase
) ces 3 commits seront éliminés en silencenewbranch
! (voir explication ci-dessous)Au lieu de cela, procédez comme suit:
--keep
est similaire--hard
, mais plus sûr, car échoue plutôt que de supprimer les modifications non validées).newbranch
.newbranch
. Puisqu'ils ne sont plus référencés par une branche, il le fait en utilisant le reflog de git :HEAD@{2}
est le commit quiHEAD
faisait référence à 2 opérations auparavant, c'est-à-dire avant que nous 1. vérifionsnewbranch
et 2. utiliségit reset
pour rejeter les 3 commits.Attention: le reflog est activé par défaut, mais si vous l'avez désactivé manuellement (par exemple en utilisant un dépôt git "nu"), vous ne pourrez pas récupérer les 3 commits après avoir exécuté
git reset --keep HEAD~3
.Une alternative qui ne repose pas sur le reflog est:
(si vous préférez, vous pouvez écrire
@{-1}
- la branche précédemment vérifiée - au lieu deoldbranch
).Explication technique
Pourquoi
git rebase
rejeter les 3 commits après le premier exemple? C'est parcegit rebase
que sans argument active l'--fork-point
option par défaut, qui utilise le reflog local pour essayer d'être robuste contre la branche en amont poussée de force.Supposons que vous ayez dérivé origine / master lorsqu'il contenait des validations M1, M2, M3, puis que vous ayez effectué trois validations vous-même:
mais ensuite quelqu'un réécrit l'histoire en poussant force / origin pour supprimer M2:
En utilisant votre reflog local, vous
git rebase
pouvez voir que vous êtes issu d'une incarnation antérieure de la branche origine / maître, et donc que les validations M2 et M3 ne font pas vraiment partie de votre branche de sujet. Par conséquent, il suppose raisonnablement que puisque M2 a été supprimé de la branche en amont, vous ne le souhaitez plus dans votre branche de sujet une fois que la branche de thème est rebasée:Ce comportement est logique et est généralement la bonne chose à faire lors du rebasage.
Donc, la raison pour laquelle les commandes suivantes échouent:
est parce qu'ils laissent le reflog dans le mauvais état. Git voit
newbranch
comme ayant bifurqué la branche amont lors d'une révision qui inclut les 3 validations, puisreset --hard
réécrit l'historique de l'amont pour supprimer les validations, et donc la prochaine fois que vous l'exécutez,git rebase
il les supprime comme toute autre validation qui a été supprimée de l'amont.Mais dans ce cas particulier, nous voulons que ces 3 commits soient considérés comme faisant partie de la branche du sujet. Pour y parvenir, nous devons bifurquer en amont lors de la révision précédente qui n'inclut pas les 3 commits. C'est ce que mes solutions suggérées font, donc elles laissent toutes deux le reflog dans l'état correct.
Pour plus de détails, voir la définition de
--fork-point
dans les documents git rebase et git merge-base .la source
master
. Alors non, ils n'ont pas dangereusement tort.-t
vous faites référence segit branch
produit implicitement si vous avezgit config --global branch.autosetuprebase always
défini. Même si vous ne le faites pas, je vous ai déjà expliqué que le même problème se produit si vous configurez le suivi après avoir exécuté ces commandes, comme l'OP a probablement l'intention de le faire compte tenu de leur question.Solution beaucoup plus simple utilisant git stash
Voici une solution beaucoup plus simple pour les validations dans la mauvaise branche. Commencer sur une branche
master
qui a trois commits erronés:Quand l'utiliser?
master
Ce que cela fait, par numéro de ligne
master
, mais laisse tous les fichiers de travail intactsmaster
arborescence de travail exactement égale à l'état HEAD ~ 3newbranch
Vous pouvez maintenant utiliser
git add
etgit commit
comme vous le feriez normalement. Tous les nouveaux commits seront ajoutés ànewbranch
.Ce que cela ne fait pas
Buts
Le PO a déclaré que l'objectif était de "ramener le maître avant que ces commits ne soient effectués" sans perdre les modifications et cette solution le fait.
Je le fais au moins une fois par semaine lorsque je fais accidentellement de nouveaux commits au
master
lieu dedevelop
. Habituellement, je n'ai qu'une seule validation de restauration, auquel cas l'utilisationgit reset HEAD^
de la ligne 1 est un moyen plus simple de restaurer une seule validation.Ne faites pas cela si vous avez poussé les changements de master en amont
Quelqu'un d'autre a peut-être tiré ces changements. Si vous ne réécrivez que votre maître local, il n'y a aucun impact lorsqu'il est poussé en amont, mais pousser un historique réécrit aux collaborateurs peut provoquer des maux de tête.
la source
git add
etgit commit
que j'ai utilisées, donc tout ce que j'avais à faire était d'appuyer sur la flèche vers le haut et d'entrer quelques fois et boum! Tout était de retour, mais sur la bonne branche maintenant.Cela ne les "déplace" pas au sens technique mais cela a le même effet:
la source
rebase
pour la même chose?rebase
sur la branche détachée dans le scénario ci-dessus.Pour ce faire sans réécrire l'historique (c'est-à-dire si vous avez déjà poussé les commits):
Les deux branches peuvent alors être poussées sans force!
la source
Eu juste cette situation:
J'ai joué:
Je m'attendais à ce que je devienne le HEAD, mais le commit L l'est maintenant ...
Pour être sûr d'atterrir au bon endroit dans l'histoire, il est plus facile de travailler avec le hachage du commit
la source
Comment puis-je y aller
pour ça?
Avec deux commandes
donnant
et
donnant
la source
Si vous avez juste besoin de déplacer tous vos commits non poussés vers une nouvelle branche , il vous suffit de le faire,
créer une nouvelle branche à partir de la branche actuelle:
git branch new-branch-name
Poussez votre nouvelle branche :
git push origin new-branch-name
ramenez votre ancienne branche (actuelle) au dernier état poussé / stable:
git reset --hard origin/old-branch-name
Certaines personnes ont aussi d' autres
upstreams
plutôt queorigin
, ils devraient utiliser appropriésupstream
la source
1) Créez une nouvelle branche, qui déplace toutes vos modifications vers new_branch.
2) Revenez ensuite à l'ancienne branche.
3) Faites git rebase
4) Ensuite, l'éditeur ouvert contient les 3 dernières informations de validation.
5) Passez
pick
àdrop
tous ces 3 commits. Enregistrez puis fermez l'éditeur.6) Les 3 derniers commits sont maintenant supprimés de la branche actuelle (
master
). Poussez maintenant la branche avec force, avec un+
signe avant le nom de la branche.la source
Vous pouvez le faire en seulement 3 étapes simples que j'ai utilisées.
1) créer une nouvelle branche où vous souhaitez vous engager votre récente mise à jour.
git branch <branch name>
2) Trouver l'ID de validation récente pour la validation sur une nouvelle branche.
git log
3) Copiez cet ID de validation. Notez que la liste des validations les plus récentes a lieu en haut. afin que vous puissiez trouver votre commit. vous le trouvez également via un message.
git cherry-pick d34bcef232f6c...
vous pouvez également fournir un certain ID de validation.
git cherry-pick d34bcef...86d2aec
Maintenant, votre travail est terminé. Si vous avez choisi le bon identifiant et la bonne branche, vous réussirez. Avant de faire cela, soyez prudent. sinon un autre problème peut survenir.
Maintenant, vous pouvez pousser votre code
git push
la source
Une autre façon de procéder:
[1] Renommez la
master
branche en votrenewbranch
(en supposant que vous êtes sur lamaster
branche):[2] Créez une
master
branche à partir du commit que vous souhaitez:la source