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:
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.
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
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.
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
».
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
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. :-)
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
.
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
Au cas où vous n’auriez pas terminé la rebase et au milieu de celle-ci, les travaux suivants fonctionneront:
git rebase --abort
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
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.
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)
$
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 actuellegit checkout Origin/your-branch
# extraction au dernier état connu d’Origingit checkout -b your-branch
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
remote/your-branch
et que vous ne devez diffuser que your-branch
.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).
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.
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.
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
git reset --hard Origin/{branchName}
est la bonne solution pour réinitialiser toutes vos modifications locales effectuées par rebase.