Comment récupérer un commit perdu dans Git?

Réponses:

589

git reflogest votre ami. Recherchez le commit sur lequel vous souhaitez figurer dans cette liste et vous pouvez le réinitialiser (par exemple:) git reset --hard e870e41.

(Si vous n'avez pas validé vos modifications ... vous pourriez avoir des problèmes - engagez-vous tôt et engagez-vous souvent!)

ambre
la source
5
Jetez un oeil à git log HEAD@{1}. Si cela ressemble à la bonne série de validations, vous pouvez git reset HEAD@{1}.
Amber
4
Seulement si les codes sont mis en scène (en utilisant git add), ils sont conservés dans git et peuvent être retrouvés facilement en utilisant des commandes comme git fsck --lost-found.
Landys
2
J'ai accidentellement abandonné un commit que j'aurais dû garder lors du rebasage. Cela m'a totalement évité de refaire deux heures de travail.
josephting le
27
Cela m'a sauvé la vie.
Lutaaya Huzaifah Idris
6
Cela a sauvé ma raison: D
Frank Fajardo
120

Avant de répondre, ajoutons un peu de contexte, expliquant ce que HEADc'est.

First of all what is HEAD?

HEADest simplement une référence au commit actuel (le plus récent) sur la branche courante.
Il ne peut y en avoir qu'un seul HEADà un moment donné (à l'exclusion git worktree).

Le contenu de HEADest stocké à l'intérieur .git/HEADet contient les 40 octets SHA-1 du commit actuel.


detached HEAD

Si vous n'êtes pas sur le dernier commit - ce qui signifie qu'il HEADpointe vers un commit précédent dans l'historique, il est appelé detached HEAD.

Entrez la description de l'image ici

Sur la ligne de commande, il ressemblera à ceci - SHA-1 au lieu du nom de la branche car le HEADne pointe pas vers la pointe de la branche actuelle:

Entrez la description de l'image ici

Entrez la description de l'image ici


Quelques options sur la façon de récupérer à partir d'une tête détachée:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Cela va extraire une nouvelle branche pointant vers le commit souhaité.
Cette commande extrait un commit donné.
À ce stade, vous pouvez créer une branche et commencer à travailler à partir de ce point.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Vous pouvez toujours utiliser le reflogaussi.
git reflog affichera tout changement qui a mis à jour le HEADet vérifier l'entrée de reflog souhaitée mettra le HEADdos à ce commit.

Chaque fois que le HEAD est modifié, il y aura une nouvelle entrée dans le reflog

git reflog
git checkout HEAD@{...}

Cela vous ramènera à votre engagement souhaité

Entrez la description de l'image ici


git reset --hard <commit_id>

"Déplacer" votre HEAD vers le commit souhaité.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Remarque: ( depuis Git 2.7 ), vous pouvez également utiliser le git rebase --no-autostash.

git revert <sha-1>

"Annuler" la validation ou la plage de validation donnée.
La commande de réinitialisation "annulera" toutes les modifications apportées au commit donné.
Un nouveau commit avec le patch d'annulation sera validé tandis que le commit d'origine restera également dans l'historique.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Ce schéma illustre quelle commande fait quoi.
Comme vous pouvez le voir, reset && checkoutmodifiez le HEAD.

Entrez la description de l'image ici

CodeWizard
la source
2
Vous êtes un héros, monsieur
dylanh724
4
Cela m'a sauvé de nombreuses heures de travail. J'ai utilisé "git reflog --date = iso" pour voir la date / heure de chaque entrée car je ne pouvais pas dire avec certitude sans l'horodatage.
MetalMikester
1
pour moi, en git reset --hard <commit_id>enlevant HEADtravaillé! +1 pour la représentation graphique !!.
reverie_ss
Juste pour mentionner: si vous connaissez le nom de la branche: git reflog <branchname>peut être très utile, car vous voyez les changements d'une seule branche.
Markus Schreiber
35

Une autre façon d'accéder au commit supprimé est avec la git fsckcommande.

git fsck --lost-found

Cela produira quelque chose comme à la dernière ligne:

dangling commit xyz

Nous pouvons vérifier qu'il s'agit du même commit en utilisant reflogcomme suggéré dans d'autres réponses. Maintenant, nous pouvons faire ungit merge

git merge xyz

Remarque:
Nous ne pouvons pas récupérer la validation avec fscksi nous avons déjà exécuté une git gccommande qui supprimera la référence à la validation suspendue.

Atri
la source
3
C'est la seule réponse qui fonctionne si vous n'avez pas récemment pointé le commit en question, par exemple lorsque vous récupérez une branche puis réinitialisez accidentellement cette branche ailleurs.
TamaMcGlinn