Git: Récupérer la branche supprimée (distante)

94

J'ai besoin de récupérer deux branches Git que j'ai supprimées d'une manière ou d'une autre lors d'un push.

Ces deux branches ont été créées sur un système différent et ensuite poussées vers mon référentiel «partagé» (github).

Sur mon système, j'ai (apparemment) récupéré les branches lors d'une récupération:

~/myfolder> git fetch
remote: Counting objects: 105, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 62 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (62/62), done.
From github.com:mygiturl
 * [new branch]      contact_page -> origin/contact_page
   731d1bb..e8b68cc  homepage   -> origin/homepage
 * [new branch]      new_pictures -> origin/new_pictures

Juste après, j'ai fait un effort pour envoyer mes modifications locales au repo central. Pour une raison quelconque, ces branches ont été supprimées à la fois de mon système local et du dépôt central:

~/myfolder> git push
Counting objects: 71, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (43/43), done.
Writing objects: 100% (49/49), 4.99 KiB, done.
Total 49 (delta 33), reused 0 (delta 0)
To [email protected]:mygiturl.git
 - [deleted]         contact_page
 + e8b68cc...731d1bb homepage -> homepage (forced update)
   bb7e9f2..e0d061c  master -> master
 - [deleted]         new_pictures
   e38ac2e..bb7e9f2  origin/HEAD -> origin/HEAD
   731d1bb..e8b68cc  origin/homepage -> origin/homepage
   e38ac2e..bb7e9f2  origin/master -> origin/master
 * [new branch]      origin/contact_page -> origin/contact_page
 * [new branch]      origin/new_pictures -> origin/new_pictures

Ce n'est pas très facile de retirer les branches de leur machine de naissance, alors j'aimerais essayer de les récupérer auprès de ma section locale si possible.

Toutes les informations git "undo" que j'ai recherchées sur Google doivent récupérer les commits perdus. Je ne pense pas que cela s'applique ici, car je n'ai pas d'UID de validation pour ces branches.

J'aimerais savoir comment je peux les récupérer. J'aimerais également savoir comment ils ont été supprimés en premier lieu et comment je peux éviter cela à l'avenir.

EDIT: sur demande, voici ma configuration de repo

user.name=Craig Walker
[email protected]
alias.unadd=reset HEAD
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
[email protected]:MyGitURL.git
remote.origin.mirror=true
branch.master.remote=origin
branch.master.merge=refs/heads/master
alias.undo=reset --hard
alias.test=push -f ci HEAD:master
alias.st=status
alias.ci=commit
alias.br=branch
alias.co=checkout
alias.ch=checkout
alias.df=diff
alias.lg=log -p
alias.who=shortlog -s --
remote.ci.url=ContinuousIntegrationGitURL
remote.ci.fetch=+refs/heads/*:refs/remotes/ci/*
branch.photo.remote=origin
branch.photo.merge=refs/heads/photos
remote.foo.url=FooGitURL
remote.foo.fetch=+refs/heads/*:refs/remotes/cynthia/*
branch.homepage.remote=origin
branch.homepage.merge=refs/heads/homepage
Craig Walker
la source
Il semble que vous ayez une configuration d'extraction et de transmission «inhabituelle» ou incohérente. Que git config -lmontre le référentiel local?
CB Bailey
Très probablement; Je l'ai posté.
Craig Walker
2
Votre remote.origin.fetchrefspec n'est pas approprié pour une utilisation avec remote.origin.mirror = true. Voulez-vous mettre en miroir ou voulez-vous utiliser le dépôt GitHub comme une télécommande normale? Ma réponse devrait avoir les commandes dont vous avez besoin de toute façon.
Chris Johnsen
Je suppose qu'avec le 2ème référentiel, la mise en miroir n'est plus une option (cela a probablement causé la suppression en premier lieu).
Craig Walker

Réponses:

103

Je ne suis pas un expert. Mais tu peux essayer

git fsck --full --no-reflogs | grep commit

pour trouver le commit HEAD de la branche supprimée et les récupérer.

iamamac
la source
J'ai essayé fsck plus tôt; savez-vous comment savoir quel commit est le bon? J'en ai 20 à essayer.
Craig Walker
1
Cela l'a fait; une fois que j'ai eu les messages de validation, git branch <uid>je les ai récupérés. Merci!
Craig Walker
Bon à entendre. Assurez-vous également de résoudre le conflit entre vos paramètres remotes.origin.mirroret vos remotes.origin.fetchparamètres, sinon vous risquez de rencontrer à nouveau le problème (ou de supprimer involontairement les commits poussés à partir d'autres dépôts).
Chris Johnsen
@Craig: Content d'être utile :)
iamamac
3
J'ai perdu une branche candidate à la libération aujourd'hui. Je ne connaissais pas l'ID de validation. git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
Je l'ai
23

juste deux commandes me sauvent la vie

1. Cela listera tous les HEAD précédents

git reflog

2. Cela rétablira la validation HEAD que vous avez supprimée.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02
chinnawatp
la source
1
Je ne me suis jamais enregistré dans la branche localement, donc mon HEAD n'y est jamais allé, donc je ne trouve pas l'ID de validation avec git reflog. Y a-t-il autre chose que je puisse essayer?
zyy
1
Identique à @zyy Le commit a été supprimé par un autre membre de l'équipe à distance, donc je dois le récupérer sur ma machine locale (je n'ai jamais eu ce commit localement) et le repousser ...
OmGanesh
11

Vos branches supprimées ne sont pas perdues, elles ont été copiées dans origin / contact_page et origin / new_pictures "branches de suivi à distance" par la récupération que vous avez montrée (elles ont également été repoussées par le push que vous avez montré, mais elles ont été poussées dans refs / remotes / origin / au lieu de refs / heads /). Vérifiez git log origin/contact_pageet git log origin/new_picturespour voir si vos copies locales sont «à jour» avec tout ce que vous pensez devrait être là. Si de nouveaux commits ont été poussés sur ces branches (à partir d'un autre dépôt) entre l'extraction et le push que vous avez montrés, vous les avez peut-être «perdus» (mais vous pourriez probablement les trouver dans l'autre dépôt qui a le plus récemment poussé ces branches) .

Conflit d'extraction / transmission

Il semble que vous récupérez dans un `` mode distant '' normal (les références / têtes distantes / sont stockées localement dans les références / télécommandes / origine /), mais en poussant en `` mode miroir '' (les références locales / sont poussées sur les références distantes /) . Vérifiez votre .git / config et réconciliez les paramètres remote.origin.fetchet remote.origin.push.

Faire une sauvegarde

Avant d'essayer des modifications, créez une simple archive tar ou zip ou l'ensemble de votre dépôt local. De cette façon, si vous n'aimez pas ce qui se passe, vous pouvez réessayer à partir d'un dépôt restauré.

Option A: reconfigurer en miroir

Si vous avez l'intention d'utiliser votre dépôt distant comme miroir de votre dépôt local, procédez comme suit:

git branch contact_page origin/contact_page &&
git branch new_pictures origin/new_pictures &&
git config remote.origin.fetch '+refs/*:refs/*' &&
git config --unset remote.origin.push &&
git config remote.origin.mirror true

Vous pourriez aussi éventuellement vouloir supprimer toutes vos références / télécommandes / origine / références, car elles ne sont pas utiles si vous travaillez en mode miroir (vos branches normales remplacent les branches de suivi à distance habituelles).

Option B: Reconfigurer en tant que télécommande normale

Mais comme il semble que vous utilisez ce dépôt distant avec plusieurs dépôts «de travail», vous ne voulez probablement pas utiliser le mode miroir. Vous pouvez essayer ceci:

git config push.default tracking &&
git config --unset remote.origin.push
git config --unset remote.origin.mirror

, Vous voudrez éventuellement ensuite supprimer les refs / faux / refs Distants origine dans votre repo à distance: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures ….

Test Push

Essayez git push --dry-runde voir ce qu'il git pushferait sans lui demander de modifier le référentiel distant. Si vous n'aimez pas ce qu'il va faire, récupérez à partir de votre sauvegarde (tar / zip) et essayez l'autre option.

Chris Johnsen
la source
1
Je ne pense pas que les branches de suivi à distance aient été conservées, si elles ont été copiées du tout. 'git branch -a' ne les montre pas, et je ne trouve pas non plus de fichiers avec ces noms dans le répertoire .git. Enfin, les commandes "git log" que vous avez recommandées renvoient "fatal: argument ambigu 'origin / contact_page': révision inconnue ou chemin non dans l'arbre de travail": - \ Merci cependant.
Craig Walker
1
Eh bien, ces branches étaient là, votre journal push le montre. Lorsque vous recherchez des références dans le .gitrépertoire, assurez-vous de vérifier .git/packed_refsen plus de .git/refs/. git show-refva vider toutes vos références locales (emballées ou «en vrac»). Vous devriez toujours être en mesure de trouver les références dans le dépôt qui les a initialement poussées vers votre dépôt GitHub (sur une machine différente? Le dépôt de quelqu'un d'autre?). A défaut, aussi longtemps que vous ne l' avez pas fait gc ou pruneau, vous devriez être en mesure de la git fscksortie d'examiner les commits ballants et les remettre en place: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen
pack_refs ne l'avait pas non plus. Les commits étaient définitivement suspendus; aucune idée de comment cela s'est passé. Merci quand même pour vôtre aide!
Craig Walker
8

Si la suppression est assez récente (comme un moment Oh-NO!), Vous devriez toujours avoir un message:

Deleted branch <branch name> (was abcdefghi).

vous pouvez toujours exécuter:

git checkout abcdefghi

git checkout -b <some new branch name or the old one>

Timmy
la source
8
  1. découvrir coimmit id

    git reflog

  2. récupérer la branche locale que vous avez supprimée par erreur

    git branch need-recover-branch-name commitId

  3. pousser à nouveau need-recover-branch-name si vous avez également supprimé la branche distante avant

    git push origin need-recover-branch-name

JackChouMine
la source
2
Cela a fonctionné pour moi. Je préfère à la réponse acceptée car il y avait beaucoup moins d'étapes. J'ai pu voir mon message de validation à partir de git reflog, plutôt que d'avoir à deviner et git show.
theUtherSide
3

Les données existent toujours dans github, vous pouvez créer une nouvelle branche à partir des anciennes données:

git checkout origin/BranchName #get a readonly pointer to the old branch
git checkout –b BranchName #create a new branch from the old
git push origin BranchName #publish the new branch
jhilden
la source
1

Je pense que vous avez une configuration incohérente pour «fetch» ​​et «push», donc cela a empêché le fetch / push par défaut de faire un aller-retour correctement. Heureusement, vous avez récupéré les branches que vous avez supprimées par la suite, vous devriez donc pouvoir les recréer avec une poussée explicite.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures
CB Bailey
la source
Comme pour mon commentaire à @Chris Johnson, il semble que les branches n'existent plus (jamais?) Localement. Quand je git push origin origin/contact_page:contact_pagereçois ceci: error: src refspec origin/contact_page does not match any
Craig Walker
OK, je pense voir ce qui s'est passé, (bien que l'erreur complète serait utile). push a mis à jour la branche supprimée et supprimé la référence localement ainsi que c'est une référence de suivi. Que git rev-parse refs/remotes/origin/origin/contact_pagedit-on? En raison de la configuration bidon de «miroir», la branche peut maintenant être référencée ici dans le référentiel local.
CB Bailey
Salut Charles; Depuis que j'ai écrit ceci, j'ai modifié (et corrigé) ma configuration afin que je ne puisse plus obtenir la sortie (méchante) de l'analyse des revues. Cependant, je ne pense pas qu'il y ait eu un répertoire "d'origine" à double emboîtement dans les télécommandes.
Craig Walker
0

Si votre organisation utilise JIRA ou un autre système similaire lié à git, vous pouvez trouver les commits répertoriés sur le ticket lui-même et cliquer sur les liens vers les modifications de code. Github supprime la branche, mais les commits sont toujours disponibles pour le tri sélectif.

Roralee
la source
-1

Cela peut sembler trop prudent, mais je zip fréquemment une copie de tout ce sur quoi j'ai travaillé avant d'apporter des modifications au contrôle de code source. Dans un projet Gitlab sur lequel je travaille, j'ai récemment supprimé une branche distante par erreur que je voulais conserver après la fusion d'une demande de fusion. Il s'est avéré que tout ce que j'avais à faire pour le récupérer avec l'historique des validations était de pousser à nouveau. La demande de fusion était toujours suivie par Gitlab, elle affiche donc toujours l'étiquette bleue «fusionnée» à droite de la branche. J'ai toujours compressé mon dossier local au cas où quelque chose de grave se produirait.

Artorias2718
la source