Comment puis-je annuler reset --hard HEAD~1?
13 réponses
Pat Notz est correct. Vous pouvez obtenir le retour de commit aussi longtemps que cela a été dans quelques jours. Git ne collecte que les ordures après environ un mois ou plus à moins que vous lui dites explicitement d'enlever les nouvelles taches.
$ git init
Initialized empty Git repository in .git/
$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file2
$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1
$ cat file2
cat: file2: No such file or directory
$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2
$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2
$ cat file2
added new file
vous pouvez voir dans l'exemple que le file2 a été enlevé à la suite de la réinitialisation dure, mais a été remis en place lorsque j'ai réinitialisé via le reflog.
Ce que vous voulez faire est de spécifier le sha1 de la validation que vous souhaitez restaurer. Vous pouvez obtenir le sha1 en examinant le reflog ( git reflog
) et puis faire
git reset --hard <sha1 of desired commit>
Mais n'attendez pas trop longtemps... après quelques semaines, git finira par voir que commit n'est pas référencé et supprimera tous les blobs.
la réponse est cachée dans la réponse détaillée ci-dessus, vous pouvez simplement faire:
$> git reset --hard HEAD@{1}
(voir la sortie de git reflog show )
il est possible de le récupérer si Git n'a pas encore ramassé les ordures.
obtenir un aperçu de dangling commits avec fsck
:
$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
Récupérer le balançant commit avec git rebase:
$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
si vous êtes vraiment chanceux, comme je l'étais, vous pouvez retourner dans votre éditeur de texte et appuyer sur "Annuler".
je sais que ce n'est pas vraiment une bonne réponse, mais ça m'a épargné une demi-journée de travail alors j'espère que ça fera la même chose pour quelqu'un d'autre!
exemple de cas IRL:
$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a <- it's this one
$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a
commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date: Wed Aug 15 08:41:30 2012 +0200
*MY COMMIT MESSAGE IS DISPLAYED HERE*
diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*
$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a
First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.
autant que je sache, --hard
rejettera les changements non engagés. Puisqu'ils ne sont pas suivis par git. mais vous pouvez annuler le discarded commit
.
$ git reflog
aura des listes:
b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....
où 4bac331
est le discarded commit
.
maintenant, il suffit de déplacer la tête à ce commit::
$ git reset --hard 4bac331
Dans la plupart des cas, oui.
selon l'état dans lequel se trouvait votre dépôt lorsque vous avez exécuté la commande, les effets de git reset --hard
peuvent varier de trivial à undo, à fondamentalement impossible.
ci-dessous, j'ai énuméré une gamme de différents scénarios possibles, et comment vous pourriez vous en remettre.
tous mes changements ont été commis, mais maintenant les commits sont partis!
cette situation se produit habituellement lorsque vous lancez git reset
avec un argument, comme dans git reset --hard HEAD~
. Ne vous inquiétez pas, c'est facile à récupérer!
si vous avez simplement couru git reset
et n'avez rien fait d'autre depuis, Vous pouvez revenir à l'endroit où vous étiez avec ce un-liner:
git reset --hard @{1}
cela réinitialise votre branche actuelle quel que soit l'état dans lequel elle se trouvait avant la dernière fois où elle a été modifiée (dans votre cas, la modification la plus récente de la branche serait la réinitialisation dure que vous essayez annuler.)
si, par contre, vous avez apporté d'autres modifications à votre branche depuis la réinitialisation, la doublure ci-dessus ne fonctionnera pas. Au lieu de ça, tu devrais courir. git reflog
<branchname>
pour voir une liste de tous les changements récents apportés à votre branche (y compris les réinitialisations). Cette liste ressemblera à quelque chose comme ceci:
7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit
trouver l'opération dans cette liste que vous souhaitez "annuler." Dans l'exemple ci-dessus, ce serait la première ligne, celle qui dit "reset: le déplacement de la TÊTE~". Ensuite, copiez la représentation de la propagation avant (ci-dessous) cette opération. Dans notre cas, ce serait master@{1}
(ou 3ae5027
, ils représentent tous les deux la même livraison), et exécuter git reset --hard <commit>
pour réinitialiser votre branche à qui s'engagent.
j'ai mis en scène mes changements avec git add
, mais jamais commis. Maintenant mes changements sont partis!
C'est un peu plus difficile à récupérer. git fait avoir des copies des fichiers que vous avez ajoutés, mais comme ces copies n'ont jamais été liées à une propagation particulière, vous ne pouvez pas restaurer les modifications en une seule fois. Au lieu de cela, vous devez localiser les fichiers individuels dans la base de données de git et les restaurer manuellement. Vous pouvez le faire en utilisant git fsck
.
pour plus de détails, voir annuler la réinitialisation -- dur avec des fichiers non engagés dans la zone de transit .
j'ai eu des changements dans les fichiers de mon répertoire de travail que je n'ai jamais mis en scène avec git add
, et jamais commis. Maintenant mes changements sont partis!
Uh oh. Je déteste te dire ça, mais tu n'as probablement pas de chance. git ne stocke pas les modifications que vous n'ajoutez pas ou que vous n'engagez pas, et selon la documentation pour git reset
:
--hard
réinitialise l'index et l'arbre de travail. toute modification apportée aux fichiers suivis dans l'arbre de travail depuis
<commit>
est écartée.
il est possible que vous pourrait être en mesure de récupérer vos modifications avec une sorte d'utilitaire de récupération de disque ou un service professionnel de récupération de données, mais à ce point c'est probablement plus de problèmes que il vaut la peine.
si vous n'avez pas encore ramassé les déchets de votre dépôt (par exemple en utilisant git repack -d
ou git gc
, mais notez que le ramassage des déchets peut aussi se faire automatiquement), alors votre propagation est toujours là – elle n'est tout simplement plus accessible à travers la tête.
vous pouvez essayer de trouver votre commit en regardant à travers la sortie de git fsck --lost-found
.
les nouvelles versions de Git ont quelque chose appelé le "refrog", qui est un journal de tous les changements qui sont les modifications apportées aux RFE (par opposition aux modifications apportées au contenu du dépôt). Ainsi, par exemple, chaque fois que vous changez de tête (c.-à-d. chaque fois que vous faites un git checkout
pour changer de branche) qui sera enregistré. Et, bien sûr, votre git reset
a aussi manipulé la tête, donc il a aussi été enregistré. Vous pouvez accéder aux États plus anciens de vos refs de la même manière que vous pouvez accéder aux États plus anciens de votre dépôt, en utilisant un signe @
au lieu d'un ~
, comme git reset HEAD@{1}
.
il m'a fallu un certain temps pour comprendre quelle est la différence entre la tête@{1} et la tête~1, Donc voici une petite explication:
git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog
ainsi, HEAD~1
signifie" aller à la Commission avant la commission que la tête pointe actuellement", tandis que HEAD@{1}
signifie "aller à la commission que la tête pointe avant qu'elle pointe à l'endroit où elle pointe actuellement".
qui vous permettra facilement de retrouver votre commit perdu et de le récupérer.
je sais que c'est un vieux fil... mais comme beaucoup de gens sont à la recherche de moyens pour défaire les choses en Git, je pense toujours que ce peut être une bonne idée de continuer à donner des conseils ici.
quand vous faites un "ajouter git" ou déplacer quoi que ce soit du haut gauche au bas gauche dans Git gui le contenu du fichier est stocké dans un blob et le contenu du fichier est possible de récupérer à partir de ce blob.
donc il est possible de récupérer un fichier même s'il n'a pas été commis mais il a avoir été ajouté.
git init
echo hello >> test.txt
git add test.txt
maintenant le blob est créé mais il est référencé par l'index de sorte qu'il ne sera pas listé avec git fsck jusqu'à ce que nous réinitialisions. Nous avons donc réinitialiser...
git reset --hard
git fsck
, vous obtiendrez une pendantes goutte ce013625030ba8dba906f756967f9e9ca394464a
git show ce01362
vous donnera le contenu du fichier "hello" retour
pour trouver des commits non référencés j'ai trouvé une astuce quelque part suggérant ceci.
gitk --all $(git log -g --pretty=format:%h)
j'ai comme un outil git gui et il est très pratique.
avant de répondre permet d'ajouter un arrière-plan, expliquant ce qu'est ce HEAD
.
First of all what is HEAD?
HEAD
est simplement une référence à la propagation actuelle (la dernière) sur la branche courante.
Il ne peut y avoir qu'un seul HEAD
à tout moment. (à l'exclusion de git worktree
)
Le contenu de HEAD
est stocké dans .git/HEAD
et il contient les 40 octets SHA-1 de la propagation courante.
detached HEAD
si vous n'êtes pas sur le dernier commit-ce qui signifie que HEAD
pointe à un commit antérieur dans l'histoire son appelé detached HEAD
.
sur la ligne de commande il ressemblera à ceci-SHA-1 au lieu du nom de la branche puisque le HEAD
ne pointe pas vers le bout de la branche actuelle
quelques options pour récupérer 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
ceci va vérifier la nouvelle branche pointant vers la propagation désirée.
Cette commande va passer à une validation donnée.
À 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 reflog
.
git reflog
affichera toutes les modifications qui ont mis à jour le HEAD
et la vérification de l'entrée désirée reflog placera le HEAD
de nouveau à cette propagation.
chaque fois que la tête est modifiée il y aura une nouvelle entrée dans le reflog
git reflog
git checkout HEAD@{...}
Cela va vous ramener à votre souhaité s'engager
git reset HEAD --hard <commit_id>
Déplacer " de votre tête en arrière pour l'souhaité s'engager.
# 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.
- Note: ( Since Git 2.7 )
vous pouvez aussi utiliser legit rebase --no-autostash
.
git revert <sha-1>
"annuler"la plage de propagation.
La commande reset" défait " toute modification apportée à la propagation.
Un nouveau commit avec le patch undo sera Commité alors que le commit original restera aussi dans l'histoire.
# add 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 il reset && checkout
modifier le HEAD
.
a créé un petit script pour faciliter légèrement la recherche de la propagation recherchée:
git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'
Oui, il peut être considérablement plus joli avec awk ou quelque chose comme ça, mais c'est simple et j'en avais juste besoin. Ça pourrait sauver quelqu'un d'autre 30 secondes.
je viens de faire une remise à zéro sur le mauvais projet. Ce qui m'a sauvé la vie, C'est L'histoire locale D'Eclipse. IntelliJ idée est dit avoir un, aussi, et ainsi que votre éditeur, il est intéressant de vérifier: