web-dev-qa-db-fra.com

Annuler un rebase git

Est-ce que quelqu'un sait comment défaire facilement un git rebase?

La seule façon qui me vienne à l’esprit est d’y aller manuellement:

  • git checkout le parent engagé dans les deux branches 
  • puis créez une branche temporaire à partir de là
  • sélectionner tous les commits à la main
  • remplacer la branche dans laquelle j'ai rebasé par la branche créée manuellement

Dans ma situation actuelle, ça va marcher parce que je peux facilement repérer les commits des deux branches (l’une était pour moi, l’autre était pour mon collègue).

Cependant, mon approche me semble suboptimale et sujette aux erreurs (disons que je venais de changer de base avec 2 de mes propres branches).

Des idées?

Précision: je parle d’un rebasement au cours duquel plusieurs commits ont été rejoués. Non seulement un.

2632
webmat

Le moyen le plus simple serait de trouver le chef de la branche tel qu'il était juste avant le début de la réabonnement dans reflog ...

git reflog

et pour réinitialiser la branche actuelle sur celle-ci (avec les mises en garde habituelles concernant la certitude absolue avant de procéder à la réinitialisation avec l'option --hard).

Supposons que l'ancien commit était HEAD@{5} dans le journal de référence:

git reset --hard HEAD@{5}

Sous Windows, vous devrez peut-être citer la référence:

git reset --hard "HEAD@{5}"

Vous pouvez vérifier l’historique de l’ancienne tête candidate en effectuant simplement un git log HEAD@{5} (Windows:git log "HEAD@{5}").

Si vous n'avez pas désactivé les modifications par branche, vous devriez pouvoir simplement faire git reflog branchname@{1} car une rebase détache la tête de la branche avant de la rattacher à la tête finale. Je revérifierais ceci, bien que comme je ne l’aie pas vérifié récemment.

Par défaut, tous les reflogs sont activés pour les référentiels non-nus:

[core]
    logAllRefUpdates = true
3645
CB Bailey

En fait, rebase enregistre votre point de départ dans ORIG_HEAD, ce qui est généralement aussi simple que:

git reset --hard ORIG_HEAD

Cependant, les variables reset, rebase et merge enregistrent toutes votre pointeur HEAD original dans ORIG_HEAD. Ainsi, si vous avez exécuté l'une de ces commandes depuis le changement de base que vous essayez d'annuler, vous devrez utiliser le reflog.

1297
Pat Notz

La réponse de Charles fonctionne, mais vous voudrez peut-être faire ceci:

git rebase --abort

nettoyer après la reset

Sinon, vous pourriez recevoir le message «Interactive rebase already started».

338
Allan

git reflog vous montrera toutes les modifications avant et après la base, et vous permettra de trouver la bonne à réinitialiser. Mais je suis surpris que personne n'ait mentionné cette autre manière très simple ici:

Rebase laisse l'ancien état en tant que ORIG_HEAD, vous pouvez donc rétablir le dernier rebase en exécutant:

git reset --hard ORIG_HEAD
80
Meligy

Réinitialiser la branche sur l'objet de validation suspendu de son ancienne astuce est bien sûr la meilleure solution car elle restaure l'état précédent sans aucun effort. Mais si vous avez perdu ces commits (par exemple, parce que vous avez collecté votre dépôt entre-temps, ou s'il s'agit d'un nouveau clone), vous pouvez toujours rebaser la branche. La clé est le commutateur --onto.

Imaginons que vous ayez une branche de sujet appelée topic et que vous ayez dérivé master lorsque la pointe de master était le 0deadbeef commit. À un moment donné, sur la branche topic, vous avez git rebase master. Maintenant, vous voulez annuler cela. Voici comment:

git rebase --onto 0deadbeef master topic

Cela prendra tous les commits sur topic qui ne sont pas sur master et les rejouer au-dessus de 0deadbeef.

Avec --onto, vous pouvez réorganiser votre historique en pratiquement toute forme.

S'amuser. :-)

79
Aristotle Pagaltzis

En fait, je mets une étiquette de sauvegarde sur la branche avant d'effectuer toute opération non triviale (la plupart des rebases sont triviales, mais je le ferais si elles avaient l'air complexes).

Ensuite, la restauration est aussi simple que git reset --hard BACKUP.

64
Alex Gontmakher

Au cas où vous aviez poussé votre branche vers un référentiel distant (généralement il s’agit de Origin) et que vous avez ensuite procédé à une rebase réussie (sans fusion) (git rebase --abort donne "Aucune rebase en cours"), vous pouvez facilement réinitialiser la branche en utilisant command:

git reset --hard Origin/{branchName}

Exemple:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'Origin/{branchName}' by 135 commits.
  (use "git Push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard Origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'Origin/{branchName}.

nothing to commit, working directory clean
57
Maksym

Au cas où vous n’auriez pas terminé la rebase et au milieu de celle-ci, les travaux suivants fonctionneront:

git rebase --abort
51
Alex

Utiliser reflog n'a pas fonctionné pour moi.

Ce qui a fonctionné pour moi était semblable à celui décrit ici . Ouvrez le fichier dans .git/logs/refs nommés d'après la branche rebasée et recherchez la ligne contenant "rebase finsihed", quelque chose comme:

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Commander le deuxième commit répertorié sur la ligne.

git checkout 88552c8f

Une fois confirmé cela contenait mes changements perdus, j'ai ramifié et laissé échapper un soupir de soulagement.

git log
git checkout -b lost_changes
17
Kris

Pour les validations multiples, rappelez-vous que toute validation se réfère à tout l'historique ayant conduit à cette validation. Ainsi, dans la réponse de Charles, lisez "l'ancien commit" comme "le plus récent de l'ancien commet". Si vous réinitialisez ce commit, alors tout l'historique menant à ce commit réapparaîtra. Cela devrait faire ce que vous voulez.

15
Greg Hewgill

Suite à la solution de @Allan et @Zearin, j'aimerais pouvoir simplement faire un commentaire, mais je n'ai pas assez de réputation, alors j'ai utilisé la commande suivante:

Au lieu de faire git rebase -i --abort (notez le -i ), je devais simplement faire git rebase --abort ( sans le -i ).

L'utilisation simultanée de -i et de --abort fait que Git me montre une liste d'utilisation/d'options.

Mon statut de succursale précédent et actuel avec cette solution est donc:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$
11
Matheus Felipe

Si vous rebasez avec succès une branche distante et que vous ne pouvez pas git rebase --abort, vous pouvez toujours effectuer certaines astuces pour enregistrer votre travail sans avoir à forcer les envois . Supposons que votre branche actuelle qui a été rebasée par erreur s'appelle your-branch et suit Origin/your-branch.

  • git branch -m your-branch-rebased # renommer la branche actuelle
  • git checkout Origin/your-branch # extraction au dernier état connu d’Origin
  • git checkout -b your-branch
  • vérifier git log your-branch-rebased, comparer à git log your-branch et définir les validations manquantes dans your-branch
  • git cherry-pick COMMIT_HASH pour chaque commit dans your-branch-rebased
  • Poussez vos modifications. Veuillez noter que deux branches locales sont associées à remote/your-branch et que vous ne devez diffuser que your-branch.
10

Disons que je rebase maître dans ma branche de fonctionnalité et que je reçois 30 nouveaux commits qui cassent quelque chose. J'ai trouvé qu'il est souvent plus facile de supprimer les mauvais commits.

git rebase -i HEAD~31

Rebase interactive pour les 31 derniers commits (cela ne fait pas de mal si vous en choisissez beaucoup trop).

Prenez simplement les commits dont vous voulez vous débarrasser et marquez-les avec "d" au lieu de "pick". Maintenant, les commits sont supprimés, ce qui annule la nouvelle base (si vous ne supprimez que les commits que vous venez de recevoir lors de la nouvelle base).

3
Hardev

Ce que je fais habituellement c'est git reset #commit_hash

jusqu'au dernier commit où je pense que rebase n'a eu aucun effet.

alors git pull

Maintenant, votre branche devrait correspondre exactement comme les commits master et rebased ne devraient pas y être.

Maintenant, on peut simplement choisir les commits sur cette branche.

1
mrigendra

Si vous êtes sur une branche, vous pouvez utiliser:

git reset --hard @{1}

Il existe non seulement un journal de référence pour HEAD (obtenu par git reflog), il existe également des réflexions pour chaque branche (obtenu par git reflog <branch>). Donc, si vous êtes sur master alors git reflog master listera toutes les modifications apportées à cette branche. Vous pouvez vous référer à ces modifications par master@{1}, master@{2}, etc.

git rebase changera généralement HEAD plusieurs fois, mais la branche actuelle ne sera mise à jour qu'une seule fois.

@{1} est simplement un raccourci pour la branche en cours , il est donc égal à master@{1} si vous êtes sur master.

git reset --hard ORIG_HEAD ne fonctionnera pas si vous avez utilisé git reset pendant une rebase interactive.

1
devconsole

Pour les débutants/ceux qui ont trop peur d'effectuer une réinitialisation matérielle, vous pouvez extraire le commit du compte de reflog, puis l'enregistrer sous une nouvelle branche.

git reflog

Trouvez le commit juste avant de commencer à rebaser. Vous devrez peut-être faire défiler l'écran plus bas pour le trouver (appuyez sur Entrée ou sur Page suivante). Prenez note du numéro HEAD et remplacez 57:

git checkout HEAD@{57}

Passez en revue les branches/commits, si cela semble bon, créez une nouvelle branche en utilisant ce HEAD:

git checkout -b new_branch_name
0
Andrew

git reset --hard Origin/{branchName}

est la bonne solution pour réinitialiser toutes vos modifications locales effectuées par rebase.

0
Damodar P