2009-10-06 14 views
8

Tengo un compromiso en una rama remota + local y quiero descartar ese compromiso del historial y poner algunos de ellos en una rama propia.git: mejor forma de revertir git sin confirmación revertida adicional

Básicamente, en este momento tengo:

  D---E---F---G master 

Y quiero:

   E---G topic 
      /
      D master 

Eso debe ser a la vez en mi local y en el (sólo hay uno, llamado origen) repositorio remoto .

¿Cuál es la forma más limpia de obtener eso?

Además, también hay otras personas que han clonado ese repositorio y que han revisado la rama principal. Si hiciera un cambio de este tipo en el repositorio remoto, ¿funcionaría 'git pull' para que ellos también lleguen al mismo estado?

Respuesta

7

Si ha publicado, tiene razón en que no desea volver a escribir el historial de master. Lo que desea es publicar una confirmación de dominio que la devuelva al estado en que se encontraba al D, conservando su historial actual para que otros usuarios puedan fusionar o modificar su trabajo fácilmente.

Si está pensando en algún momento en el futuro para fusionar topic en master entonces lo que probablemente también quiere hacer es realizar una nueva base común entre master y topic, de modo que cuando usted posteriormente combinar topic, usted don' t pierde las confirmaciones que se revertieron en master. La forma más fácil de hacerlo es haciendo una confirmación 'rehacer' encima de la confirmación 'deshacer' que restablece master a su estado original y basando la nueva rama topic encima de eso.

# checkout master branch (currently at G) 
git checkout master 

# Reset the index to how we want master to look like 
git reset D 

# Move the branch pointer back to where it should be, leaving the index 
# looking like D 
git reset --soft [email protected]{1} 

# Make a commit (D') for the head of the master branch 
git commit -m "Temporarily revert E, F and G" 

# Create the new topic branch based on master. 
# We're going to make it on top of master and the 'undo' 
# commit to ensure that subsequent merges of master->topic 
# or topic->master don't merge in the undo. 
git checkout -b topic 

# Revert the undo commit, making a redo commit (G'). 
git revert HEAD 

Como una alternativa que podría haber hecho, comete E 'F' y G 'rehacer cada parte por separado, sino como E, F y G están ya en su historial publicada es probablemente más comprensible si sólo referencia a la' deshacer 'cometer y decir que ese compromiso se está deshaciendo. Esto es lo que hace git revert, de todos modos.

Esencialmente, lo que sabes es esto.

D -- E -- F -- G -- D'  <-- master 
        \ 
         \ 
         G' <-- topic 

Lo importante es que usted no ha reescrito la historia y el tema principal se basa en lo que se funde no querer aplicar cualquier 'deshacer' comete. Ahora puede presionar con seguridad master y topic en su repositorio remoto.

+0

Gracias, esto es exactamente lo que hice ahora (también lo que sugerí en algunos de los comentarios a Jefromi). La historia es un poco fea ahora debido a este deshacer-commit, pero no puedo hacer nada al respecto. – Albert

+0

2 semanas git usuario aquí. ¿No sería más fácil primero ramificar G a G ', y luego 'git revertir' G a D, dando como resultado D '? De esa forma no tienes que deshacer/rehacer nada, lo cual me parece mucho más seguro. (Ya he perdido ediciones irrecuperables debido a jugar con 'git reset'.) – bart

+0

@bart, eche un vistazo a' git reflog'. Las cosas que se han cometido y posteriormente se han estropeado siempre deben poder recuperarse a través del reflog, al menos durante algunos días. Sin embargo, puede perder irrevocablemente los cambios que nunca cometió. – dubiousjim

4

Puede reescribir su historial si lo desea, pero es una mala idea si alguien más tiene copias del historial. En este caso, probablemente usarías rebase interactivo: git rebase -i master topic. Esto le dará una lista de confirmaciones de maestro a tema, con consejos sobre cómo jugar con ellos. Solo necesitarás eliminar la línea que contiene la confirmación que deseas eliminar.

Dicho esto, debo recalcar que es irresponsable hacer esto si alguien más tiene este historial. Debería forzarlo a su repo central, y todos los demás tendrían que arreglar sus repositorios para que coincidan, puede ser relativamente simple o complejo dependiendo de las circunstancias.

Hay una buena sección llamada "recuperación de rebase aguas arriba" en el git-rebase man page discutiendo cómo tratar con esto, si realmente lo decide.

Editar:

Para la historia simple, un escenario común sería, después de forzar un empuje no fastforward al repositorio central (push -f), otros desarrolladores:

  • volver a su viejo maestro: git branch -m master master_old
  • obtener actualizaciones y volver a crear maestro de origen: git remote update origin; git branch master origin/master
  • rebase todas las ramas puntuales hacia New principal: git rebase --onto master master_old topic

si tienen trabajo en su rama principal, que no es de origen, sin embargo, van a tener que conseguir más elegante, rebase este trabajo y todas las ramas puntuales sobre la nueva posición del maestro ... esto debe darle una idea de por qué es tan horrible reescribir la historia que otras personas tienen. Realmente, una vez que algo ha pasado al repositorio público, debe considerarlo como un historial grabado y no como un trabajo en progreso.

+0

Ok, muchas gracias por esa información. Entonces esa no es realmente una solución porque no quiero hacer tal presión de fuerza. ¿Cuál sería la solución más limpia para obtener un resultado similar? Lo único que pensaría ahora es revertir E, F, G en master, luego crear una nueva rama de ese estado y seleccionar E y G. ¿Es eso lo que uno haría naturalmente? – Albert

+0

* No hay forma * de eliminar un compromiso del historial sin causar este tipo de problemas. No importa lo que hagas, terminarás apuntando tu referencia maestra a un compromiso que no tiene la posición previa del maestro en su historia. – Cascabel

+0

Esto se trata en gran medida en mi respuesta a su nueva versión de esta pregunta, pero para responder a su comentario: no importa cómo llegue a un estado en el que haya reescrito el historial del maestro. Aún lo habrá reescrito. Si haces todas estas cosas * localmente *, está bien. Eso se llama limpieza. Si los haces para el trabajo publicado, estás estropeando las cosas, creando un repositorio público en el que nadie puede confiar, etc. – Cascabel

-3

encuentro git stash es bastante útil

Sólo esconder a la basura y nunca mirar de nuevo.

+2

No puede esconder los cambios que ya ha cometido. –

+0

use 'git reset HEAD ^' para mostrar el compromiso sin perder los cambios. – twig

Cuestiones relacionadas