¿Puedo recuperar una rama después de su eliminación en Git?

1068

Si corro git branch -d XYZ, ¿hay alguna forma de recuperar la rama? ¿Hay alguna manera de retroceder como si no hubiera ejecutado el comando borrar rama?

prosseek
fuente
44
¡Una nota realmente impresionante sobre la respuesta aceptada es que funciona incluso si la rama se eliminó en origen! Acabo de recuperar varias ramas que ya no tenía localmente después de que se borraron accidentalmente en origen.
theblang

Respuestas:

1955

Sí, deberías poder hacer git reflogy encontrar el SHA1 para la confirmación en la punta de tu rama eliminada, luego solo git checkout [sha]. Y una vez que esté en ese compromiso, puede simplemente git checkout -b [branchname]recrear la rama desde allí.


Gracias a @Cascabel por esta versión condensada / de una sola línea.

Puedes hacerlo en un solo paso:

git checkout -b <branch> <sha>
tfe
fuente
477
Puede hacerlo en un solo paso: git checkout -b <branch> <sha>.
Cascabel
200
Consejo rápido: si acaba de eliminar la rama, verá algo como esto en su terminal: "Rama eliminada <your-branch> (was <sha>)". Y luego es súper fácil, solo úsalo <sha>. Por ejemplo, como se mencionó anteriormente -git checkout -b <branch> <sha>
Snowcrash
66
sí, simplemente desplácese hacia arriba en su terminal (a menos que lo haya hecho CMD+K)
neaumusic
42
Use git reflog --no-abbrevpara ver completo <sha>que se abrevia por defecto.
jkulak
55
Para cualquier otra persona como yo, que tuvo problemas para encontrar el sha de la rama eliminada: pude git checkout remotes/origin/deleted_branch.
Jeff Irwin
161

La mayoría de las veces las confirmaciones inalcanzables se encuentran en el registro. Entonces, lo primero que debe intentar es mirar el reflog usando el comando git reflog(que muestra el reflog para HEAD).

Quizás algo más fácil si el commit era parte de una rama específica que aún existe es usar el comando git reflog name-of-my-branch. Funciona también con un control remoto, por ejemplo, si forzó el empuje (consejo adicional: siempre prefiera en su git push --force-with-leaselugar que evite mejor los errores y sea más recuperable).


Si sus commits no están en su reflog (tal vez porque lo eliminó una herramienta de terceros que no escribe en el reflog), recuperé una rama con éxito al restablecer mi rama al sha del commit encontrado usando un comando como ese ( crea un archivo con todas las confirmaciones pendientes):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

Si debe usarlo más de una vez (o si desea guardarlo en algún lugar), también puede crear un alias con ese comando ...

git config --global alias.rescue '!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt'

y úsalo con git rescue

Para investigar las confirmaciones encontradas, puede mostrar cada confirmación utilizando algunos comandos para examinarlas.

Para mostrar los metadatos de confirmación (autor, fecha de creación y mensaje de confirmación):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Para ver también las diferencias:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Una vez que haya encontrado su confirmación, cree una rama en esta confirmación con:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

Para los que están bajo Windows y le gustan las GUI, puede recuperar fácilmente los commits (y también los archivos por etapas no comprometidos) con GitExtensions utilizando la función Repository=> Git maintenance=>Recover lost objects...


Un comando similar para recuperar fácilmente archivos borrados eliminados: https://stackoverflow.com/a/58853981/717372

Philippe
fuente
2
Enorme ayuda. Tuve un compromiso perdido que nunca estuvo en mi repositorio local. El primer comando que tienes allí me ayudó a encontrarlo en el servidor. +1
Sean Adkinson
1
¡Ese alias de Git Rescue es un regalo del cielo! ¡Muchas gracias por contribuir!
72A12F4E
2
Me salvaste la vida.
Jed Lynch
La respuesta de Patrick Koorevaar me ayudó, porque no sé mis últimas confirmaciones ramificadas eliminadas <sha>.
Monir Khan
@ Monir-Khan y? ¿Qué debo concluir? La respuesta de Patrick es solo copiar / pegar mi comando (con un error: se olvidó de filtrar los commits) ...
Philippe
45

Si desea utilizar una GUI, puede realizar toda la operación con gitk.

gitk --reflog

Esto le permitirá ver el historial de confirmación de la rama como si la rama no se hubiera eliminado. Ahora simplemente haga clic derecho en la confirmación más reciente de la rama y seleccione la opción de menú Create new branch.

sin bar
fuente
28

La solución más votada en realidad hace más de lo solicitado:

git checkout <sha>
git checkout -b <branch>

o

git checkout -b <branch> <sha>

moverlo a la nueva sucursal junto con todos los cambios recientes que haya olvidado confirmar. Esta puede no ser su intención, especialmente cuando está en el "modo de pánico" después de perder la rama.

Una solución más limpia (y más simple) parece ser la única (después de encontrar la <sha>con git reflog):

git branch <branch> <sha>

Ahora ni su rama actual ni los cambios no comprometidos se ven afectados. En cambio, solo se creará una nueva rama hasta el final <sha>.

Si no es la punta, seguirá funcionando y obtendrá una rama más corta, entonces puede volver a intentar con un <sha>nombre de rama nuevo y nuevo hasta que lo haga correctamente.

Finalmente, puede cambiar el nombre de la rama restaurada correctamente a lo que se llamó o cualquier otra cosa:

git branch -m <restored branch> <final branch>

No es necesario decir que la clave del éxito fue encontrar el compromiso correcto <sha>, así que nombra tus compromisos sabiamente :)

Dmitri Zaitsev
fuente
14

Agregando a la respuesta tfe : también está el script git-resurrect.sh en el contrib/área de las fuentes de Git (en el repositorio git.git), que podría ayudarlo.

git-resurrect <name>intenta encontrar rastros de una punta de rama llamada <name>e intenta resucitarla. Actualmente, se busca en el registro de registro los mensajes de pago y -rtambién se combinan los mensajes. Con -my -t, el historial de todas las referencias se escanea para Merge <name> into other/ Merge <other> into <name>(respectivamente) comprometer temas, lo cual es bastante lento pero le permite resucitar las ramas de temas de otras personas.

Jakub Narębski
fuente
1
Funcionó para mí ahora, aunque tuve que agregar / usr / lib / git-core / a mi PATH. Pero no realizó el milagro que esperaba :(
AmanicA
10

Usé los siguientes comandos para buscar y recuperar mi rama eliminada. Los primeros pasos son de la descripción de gcb.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Ahora busque el id de confirmación de git (GIT-SHA) en función de los comentarios de confirmación y úselo en el siguiente comando. Verifique una nueva sucursal llamada NEW-BRANCH con el GIT-SHA encontrado anteriormente:

$ git checkout -b NEW-BRANCH GIT-SHA
Patrick Koorevaar
fuente
Muchas gracias. Tomó un poco de tiempo para buscar el nombre, pero el tiempo valió la pena. Si hay una manera de buscar también en la cadena de mensaje de confirmación, sería mucho mejor.
Monir Khan
9

Si no tiene un reflog, por ejemplo. debido a que está trabajando en un repositorio desnudo que no tiene habilitado el reflog y que la confirmación que desea recuperar se creó recientemente, otra opción es encontrar objetos de confirmación creados recientemente y revisarlos.

Desde el interior del .git/objectsdirectorio ejecute:

find . -ctime -12h -type f | sed 's/[./]//g' | git cat-file --batch-check | grep commit

Esto busca todos los objetos (commits, archivos, etiquetas, etc.) creados en las últimas 12 horas y los filtra para mostrar solo commits. Verificar estos es un proceso rápido.

Sin embargo, probaría el script git-ressurect.sh mencionado en la respuesta de Jakub primero.

Robert Knight
fuente
1
Buena idea alternativa! Sin embargo, su comando arroja un error. El problema es con la parte "12h" (en realidad, la "h"). Una vez que quité la "h" funcionó bien. De man find: "-ctime n - El estado del archivo se modificó por última vez n * hace 24 horas". Entonces, también deberíamos cambiar 12 a 0.5 para tener el comportamiento esperado de las últimas 12 horas.
pagliuca
1
Estoy usando OS X 10.8 aquí, por lo que los indicadores de 'buscar' anteriores se basan en la versión que se envía.
Robert Knight
1
Sí, claro, ¡el problema es con las versiones! ¡Es por eso que voté tu respuesta en primer lugar! Acabo de comentar para que la gente se dé cuenta de que los parámetros pueden ser diferentes.
pagliuca
9

Para usuarios de GitHub sin Git instalado:

Si desea restaurarlo desde el sitio web de GitHub , puede usar su API para obtener una lista de eventos relacionados con el repositorio:

primero

  • encuentra esos SHA (hashes de confirmación):

    curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

    ... o para repositorios privados:

    curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

    (se le pedirá la contraseña de GitHub)

    • (Si el repositorio requiere autenticación de dos factores, vea los comentarios sobre esta respuesta a continuación).

próximo

  • vaya a GitHub y cree una nueva rama temporal que se eliminará para siempre ( Chrome es preferible).

   • Vaya a las ramas y elimine esa.

   •   En la misma página, sin recargar , abra DevTools, Panel de red. Ahora prepárate ...

   • Haga clic en restaurar. Notará una nueva "línea". Haga clic derecho sobre él y seleccione "Copiar como cURL" y guarde este texto en algún editor.

   • Añadir al final de la línea copiada de código, éste: -H "Cookie=".

Ahora debería obtener algo como:

    curl 'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName' -H 'Cookie:' -H 'Origin: https://github.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US' -H 'User-Agent: User-Agent' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: https://github.com/UserName/ProjectName/branches' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=token' --compressed

Último paso

  • reemplace "BranchSHA" con su SHA-hash y BranchName con el nombre deseado (Por cierto, es un gran truco para cambiar el nombre de la sucursal de la web). Si no fue demasiado lento, debe hacer esta solicitud de todos modos. Por ejemplo, solo copie y pegue en un terminal.

PD

Me doy cuenta de que esta puede no ser la "solución más simple" o la solución "correcta", pero se ofrece en caso de que alguien lo encuentre útil.

Maxim Mazurok
fuente
1
Lo anterior es uno de los pocos que no se basa git reflogy, por lo tanto, fue útil, por ejemplo, cuando eliminó una rama remota y perdió el acceso a la computadora que se hizo desde entonces, por lo que no se puede obtener nada útil reflog. Tenga en cuenta que cuando use OAuth o la autenticación de dos factores en Github, el curlcomando curl -u username:token https://api.github.com/usercurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
tendrá
@ TT-- wow, ¡me alegra que haya ayudado! y gracias por su contribución con respecto al token de autenticación :)
Maxim Mazurok
8

Según tengo entendido, si otra rama puede alcanzar la rama que se va a eliminar, puede eliminarla de forma segura utilizando

git branch -d [branch]

y tu trabajo no se pierde. Recuerde que una rama no es una instantánea, sino un puntero a una. Entonces, cuando eliminas una rama, eliminas un puntero.

Ni siquiera perderá trabajo si elimina una rama a la que no puede llegar otra. Por supuesto, no será tan fácil como verificar el hash de confirmación, pero aún puede hacerlo. Es por eso que Git no puede eliminar una rama a la que no se puede llegar mediante el uso -d. En cambio tienes que usar

git branch -D [branch]

Esto es parte de un video de Scott Chacon sobre Git. Verifique el minuto 58:00 cuando habla de ramas y cómo eliminarlas.

Introducción a Git con Scott Chacon de GitHub

fabiopagoti
fuente
77
¿Cómo está ayudando esto a responder la pregunta?
Dmitri Zaitsev
66
Decirle al autor de la pregunta que las ramas no contienen contenido, sino que en realidad son punteros. No debe tener miedo de eliminar ramas ... puede crear otras nuevas que apunten a la misma confirmación que la eliminada ... ¡Guau! Todavía recuerdo cuando hice esta pregunta. ¡Buenos tiempos de regreso al 2012!
fabiopagoti
1
Tuve que desplazar tres pantallas para AL FIN encontrar una respuesta que aborde el problema: eliminar una rama es eliminar un simple puntero. Aquí no hay pérdida de datos, lo único que hay que recuperar es hacia dónde apuntaba. Las respuestas que van directamente a reflogson simplemente exageradas.
RomainValeri
5

Asegúrese de realizar todo esto localmente y confirme que su repositorio esté en el estado que desea antes de pasar a Bitbucket Cloud. También puede ser una buena idea clonar su repositorio actual y probar estas soluciones primero.

  1. Si acaba de eliminar la rama, verá algo como esto en su terminal:
    Deleted branch <your-branch> (was <sha>)

2. Para restaurar la rama, use:

    git checkout -b <branch> <sha>

Si no conoce el 'sha' de la parte superior de su cabeza, puede:

  1. Encuentra el 'sha' para el commit en la punta de tu rama eliminada usando:
    git reflog
  1. Para restaurar la rama, use:
    git checkout -b <branch> <sha>

Si sus commits no están en su reflog:

  1. Puede intentar recuperar una rama restableciendo su rama al sha del commit encontrado usando un comando como:
    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

2.Puede mostrar cada confirmación utilizando uno de estos:

    git log -p <commit>
    git cat-file -p <commit>
uyghurbeg
fuente
4

Para recuperar una rama eliminada, primero revise el historial de reflog,

git reflog -n 60

Donde n se refiere a los últimos n commits. Luego encuentre la cabeza adecuada y cree una rama con esa cabeza.

git branch testbranch HEAD@{30}
sajin tm
fuente
4

Reescribí una rama del control remoto para tratar de borrar algunas confirmaciones que no quería e iba a elegir las correctas que quería. Por supuesto, escribí mal los SHA ...

Así es como los encontré (principalmente una interfaz / interacción más fácil de las cosas en las respuestas aquí):

Primero, genere una lista de confirmaciones sueltas en su registro. Haga esto lo antes posible y deje de funcionar, ya que el basurero puede tirarlos.

git fsck --full --no-reflogs --unreachable --lost-found > lost

Esto crea un lostarchivo con todas las confirmaciones que tendrá que ver. Para simplificar nuestra vida, eliminemos solo el SHA:

cat lost | cut -d\  -f3 > commits

Ahora tiene un commitsarchivo con todas las confirmaciones que debe buscar.

Suponiendo que está utilizando Bash, el paso final:

for c in `cat commits`; do  git show $c; read; done

Esto le mostrará la información de diff y commit para cada uno de ellos. Y espera a que presiones Enter. Ahora escriba todos los que desee, y luego selecciónelos. Una vez que haya terminado, simplemente presione Ctrl-C.

gcb
fuente
1

Primero vaya a git batch, muévase a su proyecto como:

cd android studio project
cd Myproject
then type :
git reflog

Todos ustedes tienen una lista de los cambios y el número de referencia toma el número de referencia y luego
sale del estudio de Android o del git betcha. otra solución toma el número de referencia y ve al estudio de Android, haz clic en las ramas de git y luego haz clic en la etiqueta de pago o en la revisión más allá del número de referencia y luego jaja, tienes las ramas.

FAHAD HAMMAD ALOTAIBI
fuente
1

Agregando a la respuesta de tfe, puede recuperarse con este proceso mencionado, a menos que sus confirmaciones no sean basura recolectada. La rama de Git es simplemente un puntero a una confirmación particular en el árbol de confirmación. Pero si elimina el puntero y las confirmaciones en esa rama no se fusionan con otra rama existente, entonces git lo trata como confirmaciones colgantes y las elimina durante la recolección de basura, que puede ejecutarse automáticamente periódicamente.

Si su rama no se fusionó con una rama existente, y si se recolectó basura, perderá todas las confirmaciones hasta el punto desde donde se bifurcó la rama de una rama existente.

Rajeshwar Agrawal
fuente
1

Un problema relacionado: llegué a esta página después de buscar "cómo saber qué son las ramas eliminadas".

Mientras borraba muchas ramas viejas, sentí que borré por error una de las ramas más nuevas, pero no sabía el nombre para recuperarlo.

Para saber qué ramas se eliminaron recientemente, haga lo siguiente:

Si vas a tu URL de Git, que se verá así:

https://your-website-name/orgs/your-org-name/dashboard

Luego puede ver el feed, de lo que se elimina, por quién, en el pasado reciente.

Manohar Reddy Poreddy
fuente
Por supuesto. La respuesta anterior es para GitHub. Instalamos GitHub localmente. Gracias por hacer una pregunta.
Manohar Reddy Poreddy
1

Hice esto en la computadora que eliminé la rama:

git reflog

respuesta:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

y recupero la rama con este comando:

git checkout -b newBranchName 74b2383

Ammar Bozorgvar
fuente
0

Simplemente usando git reflogno me devolvió el sha. Solo el commit id(que tiene 8 caracteres de largo y un sha es mucho más largo)

Entonces solía git reflog --no-abbrev

Y luego haga lo mismo que se mencionó anteriormente: git checkout -b <branch> <sha>

MarvinVK
fuente
siempre puedes usar el sha abreviado de 8 caracteres, no tienes que usar el sha completo
Michael Dreher
0

SI está utilizando VSCode ... y sincronizó su rama con el servidor en algún momento antes de eliminarlo ...

Tenga en cuenta que git branch delete solo elimina la copia local, no la copia en el servidor. Primero, en el panel de Git (icono de git en la barra de herramientas izquierda), mire a través de las ramas y vea si su rama todavía está allí debajo de "origin / your_branch_name". Si es así, simplemente seleccione eso y debería recuperar su código (sugiera que copie / pegue / guarde inmediatamente en otro lugar).

Si no vio un "origin / your_branch_name", instale la extensión GitLens. Esto le permite hurgar visualmente en los repositorios del servidor y ubicar la copia que sincronizó con el servidor. Si tiene múltiples repositorios, tenga en cuenta que puede ser necesario tener al menos un archivo abierto desde el repositorio deseado para que el repositorio aparezca en GitLens. Entonces:

  1. Abra el panel de GitLens

  2. Expande el repositorio

  3. Debería ver una lista de categorías: Sucursales / Colaboradores / Controles remotos / Alijos / etc.

Debería encontrar YourLostTreasure en "Ramas" o posiblemente en "Controles remotos -> Orígenes". Con suerte, verá una rama con el nombre deseado; si la expande, debería ver los archivos que cambió en esa rama. Haga doble clic en los nombres de los archivos para abrirlos e inmediatamente haga una copia de seguridad de ese código.

Si no ve de inmediato su rama perdida, mire y si encuentra algo prometedor, ábralo inmediatamente y tome el código. Tuve que hurgar un poco hasta que encontré TheGoldenBranch, e incluso entonces al código le faltaban los últimos uno o dos guardados (posiblemente porque no pude sincronizar con el servidor antes de intentar -un-Branch-Merge-pero-accidentalmente-haciendo clic- Branch-Delete). Mi búsqueda se prolongó innecesariamente porque cuando encontré la rama por primera vez, no estaba completamente seguro de que el nombre fuera correcto, así que seguí buscando y me llevó algo de tiempo volver a encontrar esa primera rama. (Por lo tanto, Carpe Carpum y luego seguir buscando).

cssyphus
fuente