realicé un git rebase master
en mi rama y no me di cuenta de que no era lo que quería hasta que lo empujé al control remoto. Solo estamos yo y otra persona trabajando en el proyecto, por lo que sé que no han realizado los últimos cambios.
Al leer otras preguntas en StackOverflow, decía usar git reflog
y entonces git reset --hard HEAD@{n}
antes de la rebase. Hice esto para ir a un compromiso que creé antes del rebase, pero no restauró las cosas como estaban antes.
¿Me estoy perdiendo un paso? ¿Hay alguna manera de hacer que la otra persona empuje su repositorio de nuevo para restaurar las cosas como estaban?
Gracias
Torek
Como ya señaló Makoto, probablemente no debería molestarse en deshacer esta reorganización: probablemente sea lo que quería. No obstante, siéntete libre de seguir leyendo para saber cómo deshacerlo.
Usa el reflog para la rama, ya que será más fácil de leer. (Los HEAD
reflog tiene la misma información, pero tiene muchas más cosas, por lo tanto, es más difícil encontrar lo que está buscando).
Por ejemplo, si acababa de cambiar la base mybranch
Yo vería:
$ git reflog mybranch
nnnnnnn mybranch@{0}: rebase finished: refs/heads/mybranch onto biguglysha1
ooooooo mybranch@{1}: commit: some sort of commit message
...
El nombre mybranch@{1}
es por lo tanto sinónimo (por el momento) de ooooooo
, el antiguo SHA-1 abreviado. Cada vez que le hace algo a la rama (como git reset
) el número dentro del @{...}
parte cambiará, mientras que los SHA-1 son permanentes para siempre, 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}
deberías tener el original de vuelta. Esto es porque rebase
simplemente copias confirma y luego mueve la etiqueta. Después del rebase, pero antes del reinicio, el gráfico de confirmación se parece a esto, donde A
mediante C
son “sus” compromisos:
A - B - C <-- (only in reflog now)
/
... - o - o - o - A' - B' - C' <-- mybranch (after rebase)
y git reset
simplemente1 borra la etiqueta de rama actual y la pega en el SHA-1 proporcionado (convirtiendo un nombre de reflog en un SHA-1 primero si es necesario). Por lo tanto, después de la reset
:
A - B - C <-- mybranch, plus older reflog
/
... - o - o - o - A' - B' - C' <-- (only in reflog now)
Tenga en cuenta que ahora, post-reset
, las copias de confirmación hechas por rebase son las “abandonadas” que solo se encuentran en las entradas de reflog. Los originales, que habían sido abandonados, ahora se reclaman bajo mybranch
otra vez.
La forma de pensar en esto es dibujar el gráfico de confirmación (con las nuevas confirmaciones que apuntan a sus confirmaciones principales), luego dibujar etiquetas de rama con flechas largas que apuntan al gráfico de confirmación. El gráfico nunca2 cambios excepto a agregar nuevo commits, que tienen SHA-1 grandes y feos nuevos y diferentes (es por eso que uso letras como A
B
y C
en su lugar, y agregue aditivos como A'
para copias). Se garantiza que los SHA-1 son únicos3 y son permanentes, pero las etiquetas con sus flechas largas se borran y se vuelven a señalar 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).
1Bien, git reset
hace más que simplemente mover la etiqueta, a menos que agregue algunos indicadores de línea de comandos. Por defecto, mueve la etiqueta y reinicia el índice; con --hard
mueve la etiqueta y reinicia el índice y limpia su árbol de trabajo. Con --soft
eso sólo mueve la etiqueta, dejando solos el índice y el árbol de trabajo. Dado que git es lo que es, hay muchas más banderas que tuercen aún más el significado, pero esas son las tres grandes: --soft
nada alias --mixed
y --hard
.
2Si git solo agregara cosas, su repositorio crecería enormemente con el tiempo. Entonces, eventualmente, las confirmaciones “inalcanzables” (aquellas sin etiquetas, y ni siquiera las entradas sobrantes de reflog, apuntan a ellas, y que no son señaladas por alguna confirmación que lo hace tener una etiqueta, o algún otro compromiso apuntado; eventualmente, estos compromisos inalcanzables (y cualquier otro objeto inalcanzable) se eliminan cuando se ejecuta git git gc
para usted automáticamente. Puede forzar que se eliminen antes, pero rara vez hay una buena razón para molestarse.
3Git en 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 lo suficientemente buena, la probabilidad es 1 de 2160, que es muy pequeño. Esto es algo bueno como el “Paradoja de cumpleaños” plantea la posibilidad con bastante rapidez, pero debido a que comenzó tan pequeño, se mantiene pequeño y en la práctica nunca ha sido un problema.
4Por diseño, la “rotura” es que git simplemente deja de agregar objetos, por lo que hasta ahora todo sigue bien. Luego, debe pasar a cualquier sistema nuevo que se haya diseñado para manejar repositorios de miles de millones de objetos, el git de “próxima generación” o lo que sea.
-
¿Cuál sería la forma correcta de extraer cambios de otra rama, como necesitaba aquí, pero sin perder el historial de confirmaciones existente de mi rama? ¿Usaría una reorganización interactiva, una fusión o?… Gracias
– usuario1960364
10 de septiembre de 2015 a las 8:56
-
no me queda claro que tú quiere decir “el historial de confirmación existente de mi sucursal”: está el historial que su git mantiene en el registro de referencia para su sucursal, y está el historial implícito en el gráfico de confirmación. En el ejemplo de mi respuesta, el historial del gráfico de compromiso es “C apunta a B, B apunta a A, A apunta a un compromiso que de otro modo no se distinguiría
o
“. Hay una historia diferente, “C’ apunta a B’, B’ apunta a A’, A’ apunta a un compromiso diferente que de otro modo no se distinguiría”. Estos son, por supuesto, diferentes, pero, si nadie se preocupa por qué cometer de otro modo mediocreo
usan, ambos están bien.– torek
10/09/2015 a las 15:53
makoto
Tengo buenas y malas noticias para ti.
¡La buena noticia es que estás en el estado en el 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 rama 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 [considered to be] algo bueno: siempre que no haya tenido ningún conflicto de fusión, no haya perdido ningún dato en este proceso y tampoco tenga una confirmación de fusión sin valor en su rama.
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 forzar la inserción, entonces alguien con un historial no extraído puede forzar la inserción de su rama en el repositorio remoto. Esto hará que el estado de su repositorio sea el que estaba en su caja en el momento en que presionaron.
-
Pero quiero mi historial de confirmaciones, ¿no hay forma de revertirlo? Como dije en mi publicación original, la persona con la que estoy trabajando no se ha desconectado, por lo que si no hay una manera de solucionarlo, ¿hay alguna manera de que pueda usar su repositorio local para restaurar al último estado en el que estaba? ? En el futuro, ¿cómo debo hacer esto para no perder mi historial de confirmaciones?
– usuario1960364
9 sep 2015 a las 23:44
-
Absolutamente. Pero quiero que entiendas dos cosas: has definitivamente historia reescrita, y eso solo debe hacerse con mucha precaución, y la situación que describe no es una mala situación en absoluto. Tiene el compromiso que desea en su rama y tiene un historial lineal más limpio. Pero, si no te sientes cómodo con eso, tu pareja puede empujar su rama a la fuerza.
– Makoto
9 sep 2015 a las 23:46
Si toma el hash de confirmación del reflog (también la cola de la entrada en un registro de git normal), puede restablecer –hard COMMIT y luego git push -f origin master, que generalmente es un cosa mala . Recomendaría consultar el historial completo en un directorio separado y limpio antes de forzar la inserción.
Elaborar “No restauró las cosas como estaban antes”.
– sam
9 sep 2015 a las 22:43
Antes de la reorganización, tenía varias confirmaciones adicionales y mensajes de confirmación que no se mostraban y el gráfico mostraba 2 niveles en lugar de solo 1.
– usuario1960364
09/09/2015 a las 22:50
Retrocedamos aquí:
git rebase master
básicamente ha tomado lo que estaba en su local master y movió su rama a la punta de lo que estaba en su rama maestra local. ¿Es el caso de que su sucursal maestra local no estaba actualizada con la sucursal remota? No va a ser un proceso simple para desenredar esto.– Makoto
9 sep 2015 a las 22:52
Estaba en maestro, hice un tirón, hice un cambio rápido y empujé eso a maestro. Quería ese cambio en branch2, así que revisé branch2 y ejecuté
git rebase master
. Todo lo que quería era que la última confirmación en master también estuviera en branch2, pero en cambio hizo otra cosa (soy nuevo en Git, así que no estoy seguro de cómo explicar lo que hizo). Pero varias confirmaciones desaparecieron o se juntaron, no estoy seguro de cuáles. Quiero volver a antes de todo esto.– usuario1960364
9 sep 2015 a las 22:57
Posible duplicado de Deshacer un git rebase
– phuclv
11 de noviembre de 2016 a las 4:29