Annuler la réinitialisation -- dur avec les fichiers non engagés dans la zone de transit

j'essaie de récupérer mon travail. J'ai bêtement fait git reset --hard , mais avant cela j'ai fait seulement get add . et n'ai pas fait git commit . S'il vous plaît aider! Voici mon journal:

MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)

#   modified:   .gitignore
...


MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api

est-il possible de défaire git reset --hard dans cette situation?

98
demandé sur Ajedi32 2011-09-10 23:28:59

7 réponses

vous devriez être en mesure de récupérer tous les fichiers que vous avez ajoutés à l'index (E. g, comme dans votre situation, avec git add . ) bien que cela puisse être un peu de travail. Afin d'ajouter un fichier à l'index, git l'ajoute à la base de données des objets, ce qui signifie qu'il peut être récupéré tant que la collecte des ordures n'a pas encore eu lieu. Il y a un exemple de comment faire ceci donné dans réponse de Jakubę Narbski ici:

cependant, j'ai essayé cela sur un dépôt de test, et il y avait un couple de problèmes - --cached devrait être --cache , et j'ai trouvé qu'il n'a pas réellement créé le répertoire .git/lost-found . Cependant, les étapes suivantes ont fonctionné pour moi:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

qui devrait sortir tous les objets dans la base de données d'objet qui ne sont pas accessibles par n'importe quelle réf, dans le de l'index, ou via le reflog. La sortie ressemblera à quelque chose comme ceci:

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03

... et pour chacune de ces taches, vous pouvez faire:

git show 907b308

Pour afficher le contenu du fichier.


trop de production?

mise à Jour en réponse à sehe commentaire ci-dessous:

si vous constatez que vous avez beaucoup de commits et d'arbres listés dans la sortie de cette commande, vous pouvez vouloir supprimer de la sortie tous les objets qui sont référencés à partir de commits non référencés. (En général, vous pouvez revenir à ces commits via le refrog de toute façon - nous sommes juste intéressés par les objets qui ont été ajoutés à l'index mais qui ne peuvent jamais être trouvés via un commit.)

tout D'abord, enregistrer la sortie de la commande, avec:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all

maintenant les noms des objets inaccessibles commet peut être trouvé avec:

egrep commit all | cut -d ' ' -f 3

donc vous pouvez trouver juste les arbres et les objets qui ont été ajoutés à l'index, mais pas commis à n'importe quel moment, avec:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
  $(egrep commit all | cut -d ' ' -f 3)

qui réduit considérablement le nombre d'objets que vous aurez à considérer.


mise à jour: Philip Oakley ci-dessous suggère une autre façon de réduire le nombre de objets à considérer, qui est de considérer simplement les fichiers les plus récemment modifiés sous .git/objects . Vous pouvez les trouver avec:

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort

(j'ai trouvé que find invocation ici .) La fin de cette liste pourrait ressembler à:

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a

Dans ce cas, vous pouvez voir ces objets:

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a

(Notez que vous devez supprimer le / à la fin du chemin d'accès pour obtenir le nom de l'objet.)

157
répondu Mark Longair 2017-05-23 12:02:34

je viens de faire un git reset --hard et j'ai perdu un commit. Mais je connaissais le hash de commit, donc j'ai pu faire git cherry-pick COMMIT_HASH pour le restaurer.

Je l'ai fait dans les minutes qui ont suivi la perte de l'engagement, pour que cela puisse fonctionner pour certains d'entre vous.

58
répondu Richard Saunders 2013-08-27 17:42:44

grâce à Mark Longair j'ai récupéré mes affaires!

J'ai d'abord sauvegardé tous les hachages dans un fichier:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes

ensuite je les mets tous (en enlevant le truc 'unreachable blob') dans une liste et je mets les données dans de nouveaux fichiers...vous devez choisir vos fichiers et les renommer à nouveau dont vous avez besoin...mais je n'avais besoin que de quelques fichiers..espérons que cela aide quelqu'un...

commits = ["c2520e04839c05505ef17f985a49ffd42809f",
    "41901be74651829d97f29934f190055ae4e93",
    "50f078c937f07b508a1a73d3566a822927a57",
    "51077d43a3ed6333c8a3616412c9b3b0fb6d4",
    "56e290dc0aaa20e64702357b340d397213cb",
    "5b731d988cfb24500842ec5df84d3e1950c87",
    "9c438e09cf759bf84e109a2f0c18520",
    ...
    ]

from subprocess import call
filename = "file"
i = 1
for c in commits:
    f = open(filename + str(i),"wb")
    call(["git", "show", c],stdout=f)
    i+=1
13
répondu Boy 2014-01-08 13:52:01

la solution de @Ajedi32 dans les commentaires a fonctionné pour moi dans exactement cette situation.

git reset --hard @{1}

notez que toutes ces solutions reposent sur le fait qu'il n'y a pas de git gc, et que certaines d'entre elles pourraient en causer un, donc je vais fermer le contenu de votre .git directory avant d'essayer quoi que ce soit de sorte que vous avez un instantané de revenir à si un ne fonctionne pas pour vous.

5
répondu Duncan McGregor 2016-01-11 19:14:36

est tombé dans le même numéro, mais n'a pas ajouté les changements à l'indice. Donc toutes les commandes ci-dessus ne m'ont pas ramené les changements désirés.

après toutes les réponses élaborées ci-dessus, c'est une allusion naïve, mais peut-être que cela sauvera quelqu'un qui n'y a pas pensé en premier, comme je l'ai fait.

désespéré, j'ai essayé de presser CTRL-Z dans mon éditeur (LightTable), une fois dans chaque onglet ouvert - ce heureusement récupéré le fichier dans cet onglet, à son dernier état avant le git reset --hard . HTH.

3
répondu olange 2016-09-30 10:59:49

Bonté divine, j'ai tiré mes cheveux jusqu'à ce que je tombe sur cette question et ses réponses. Je crois que la réponse correcte et succincte à la question posée n'est disponible que si vous faites la synthèse de deux des commentaires ci-dessus, donc ici tout est en un seul endroit:

  1. comme mentionné par chilicuil, Lancez 'git refrog' pour identifier là le commettre hachage que vous voulez revenir à

  2. comme mentionné par akimsko, vous ne voudra probablement pas choisir a moins que vous n'ayez perdu qu'un seul commit, alors vous devriez lancer ' git reset -- dur

Note pour les utilisateurs d'egit Eclipse: je n'ai pas pu trouver un moyen de faire ces étapes dans Eclipse avec egit. Fermer Eclipse, exécuter les commandes ci-dessus à partir d'une fenêtre de terminal, puis rouvrir Eclipse a fonctionné parfaitement pour moi.

1
répondu Lolo 2014-12-03 05:50:46

les solutions ci-dessus peuvent fonctionner, cependant, il ya des moyens plus simples de récupérer de cela au lieu de passer par git -s complexe annuler. Je suppose que la plupart des git-réinitialise arriver sur un petit nombre de fichiers, et si vous utilisez VIM, ce c'est peut-être la solution la plus rapide. La mise en garde est que vous devez déjà utilisez ViM's persistent-undo, que vous devriez utiliser dans les deux cas, parce que il vous offre la possibilité d'annuler un nombre illimité de changements.

Voici les étapes:

  1. dans vim appuyez sur : et tapez la commande set undodir . Si vous avez persistent undo allumé dans votre .vimrc , il affichera un résultat similaire à undodir=~/.vim_runtime/temp_dirs/undodir .

  2. dans votre déclaration de mise en pension, utilisez git log pour connaître la dernière date/heure à laquelle vous avez effectué la dernière commit

  3. undodir à l'aide de cd ~/.vim_runtime/temp_dirs/undodir .

  4. Dans ce répertoire, utilisez cette commande pour rechercher tous les fichiers que vous avez changé depuis le dernier commit

    find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"

    Ici "2018-03-20 11:24:44" est la date et l'heure de la dernière validation. Si l' date à laquelle vous avez fait le git reset --hard est "2018-03-22", puis utiliser "2018-03-22", puis utiliser "2018-03-23". C'est à cause d'une bizarrerie de trouver, là où le bas la limite est inclusive, et la limite supérieure est exclusif. https://unix.stackexchange.com/a/70404/242983

  5. allez à chacun des fichiers ouvrez-les dans vim, et faites un"plus tôt 20m". Vous pouvez trouver plus de détails sur "earlier" en utilisant "h earlier". Ici earlier 20m signifie retourner à l'état du dossier 20 minutes retour, en supposant que vous avez fait le git hard --reset , 20 minutes en arrière. Répétez cette opération sur tous les fichiers que est sortie de la commande find . Je suis sûr quelqu'un peut écrire un script qui va combiner ces choses.

0
répondu alpha_989 2018-03-21 16:56:22