specific - delete commit github
Deshacer Git Rebase (3)
git rebase master
un git rebase master
en mi sucursal y no me di cuenta de que no era lo que quería hasta que lo empujé al control remoto. Solo soy yo y otra persona que trabaja en el proyecto, así que sé que no han realizado los últimos cambios.
Al leer otras preguntas en StackOverflow, se dice que use git reflog
y luego git reset --hard HEAD@{n}
antes de la rebase. Hice esto para ir a un compromiso que creé antes de la rebase, pero no restauró las cosas a cómo era antes.
¿Me estoy perdiendo un paso? ¿Hay alguna manera de hacer que la otra persona presione su repo para que las cosas vuelvan a ser como eran?
Gracias
Como Makoto ya señaló , probablemente no deberías molestarte en deshacer esta reorganización: probablemente sea lo que querías. No obstante, siéntase libre de seguir leyendo para saber cómo deshacerlo.
Usa el reflog para la rama , ya que será más fácil de leer. (El reflog HEAD
tiene la misma información, pero contiene muchas más cosas, por lo que es más difícil encontrar lo que estás buscando).
Por ejemplo, si acabara de mybranch
, vería:
$ git reflog mybranch
nnnnnnn mybranch@{0}: rebase finished: refs/heads/mybranch onto biguglysha1
ooooooo mybranch@{1}: commit: some sort of commit message
...
Por lo tanto, el nombre mybranch@{1}
es sinónimo (en este momento) de ooooooo
, el antiguo abreviado SHA-1. Cada vez que le haga algo a la rama (como git reset
), el número dentro de la parte @{...}
cambiará, mientras que los SHA-1 son siempre permanentes, por lo que es un poco más seguro usar el SHA-1 (completo o abreviado) para cortar y pegar.
Si entonces:
$ git checkout mybranch # if needed
y:
$ git reset --hard ooooooo # or mybranch@{1}
usted debe tener el original de nuevo. Esto se debe a que rebase
simplemente copia las confirmaciones y luego mueve la etiqueta. Después de la rebase, pero antes del reinicio, el gráfico de confirmación se ve algo como esto, donde A
a C
son "sus" confirmaciones:
A - B - C <-- (only in reflog now)
/
... - o - o - o - A'' - B'' - C'' <-- mybranch (after rebase)
y git reset
simplemente 1 borra la etiqueta de la rama actual y la pega en el SHA-1 suministrado (convirtiendo un nombre de reflog en un SHA-1 primero si es necesario). Por lo tanto, después del reset
:
A - B - C <-- mybranch, plus older reflog
/
... - o - o - o - A'' - B'' - C'' <-- (only in reflog now)
Tenga en cuenta que ahora, después del reset
, las copias de confirmación hechas en base de datos son las "abandonadas" que solo se encuentran en las entradas de reutilización. Los originales, que habían sido abandonados, ahora son reclamados bajo mybranch
nuevamente.
La forma de pensar sobre esto es dibujar el gráfico de confirmación (con nuevos confirmaciones apuntando a sus confirmaciones principales), luego dibujar en las ramas de las ramas con flechas largas que apuntan a la gráfica de confirmación. El gráfico nunca cambia 2 excepto para agregar nuevos compromisos, que tienen nuevos y feos SHA-1 grandes (por lo que en su lugar utilizo letras como A
B
y C
, y pego aditivos como A''
para las copias). Se garantiza que los SHA-1 son únicos 3 y son permanentes, pero las etiquetas con sus largas flechas se borran y vuelven a apuntar todo el tiempo. (Si hace esto en una pizarra, generalmente debe usar negro para el gráfico de confirmación y un color, o varios colores, para las etiquetas).
1 Bueno, git reset
hace más que solo mover la etiqueta, a menos que agregue algunos indicadores de línea de comando. Por defecto, mueve la etiqueta y restablece el índice; con --hard
, mueve la etiqueta y restablece el índice y limpia su árbol de trabajo. Con --soft
simplemente mueve la etiqueta, dejando solo el índice y el árbol de trabajo. Dado que git es lo que es, hay muchas otras banderas que retuerzan aún más el significado, pero esas son las tres grandes: --soft
, nothing aka --mixed
, y --hard
.
2 Si git solo añadiera cosas, su repo crecería enormemente con el tiempo. Entonces, eventualmente, los compromisos "inalcanzables", aquellos que no tienen etiquetas, y ni siquiera las entradas remanentes de reflog, las señalan, y que no están señalados por algún compromiso que tenga una etiqueta, u otro tipo de compromiso señalado ... finalmente, estos compromisos inalcanzables (y cualquier otro objeto inalcanzable) se eliminan cuando git ejecuta git gc
de forma automática. Puede obligar a que se eliminen antes, pero rara vez hay una buena razón para molestar.
3 Git sí depende de la garantía. Es matemáticamente posible, pero extremadamente improbable, que dos objetos diferentes terminen con el mismo SHA-1. Si esto sucede, Git se rompe. 4 Si la distribución es suficientemente buena, la probabilidad es 1 de 2 160 , lo que es realmente pequeño. Esto es bueno, ya que la "paradoja del cumpleaños" plantea la posibilidad con bastante rapidez, pero como comenzó tan pequeña, sigue siendo pequeña y en la práctica nunca ha sido un problema.
4 Por diseño, la "rotura" es que git simplemente deja de agregar objetos, por lo que todo está muy bien hasta ahora. Luego, debe pasar a cualquier sistema nuevo que haya sido diseñado para manejar los repositorios de miles de millones de objetos, el git de "próxima generación" o lo que sea.
Si tomas el hash de confirmación del reflog (también la cola de la entrada en un registro de git normal) puedes restablecer --hard COMMIT y luego git push -f origin master, que normalmente es algo malo . Recomendaría consultar el historial completo en un directorio separado y limpio antes de hacer un empuje forzado.
Tengo buenas y malas noticias para ti.
La buena noticia es que estás en el estado en que expresas lo que quieres . El último compromiso en master
está de hecho ahora en tu rama, y todo está bien con el universo.
La mala noticia es que ahora, con su operación de rebase, ha movido efectivamente su sucursal a la punta del maestro; es decir, su rama de desarrollo ahora está en el mismo estado que si simplemente se hubiera ramificado desde la punta del maestro.
Pero esto [es considerado] algo bueno: siempre que no haya tenido ningún conflicto de combinación, no ha perdido ningún dato en este proceso, y tampoco tiene un compromiso de fusión sin valor en su sucursal.
El libro hace un gran trabajo explicando qué es un rebase , así que no lo repetiré. De las operaciones que describe, no debería haber perdido ningún trabajo.
Si desea recrear su historial original antes de forzarlo, entonces alguien con un historial no extraído puede forzar su sucursal al repositorio remoto. Esto hará que el estado de su repo sea lo que estaba en su caja en el momento en que presionaron.