2008-10-15 28 views
23

Suponga que tiene:git: calabaza/corrección anterior cometer

A-B-C 

Ahora falla su construcción/prueba. La solución debería fusionarse en A. Mi flujo de trabajo actual es la siguiente:

$ git commit -m "fixA" 

A-B-C-fixA 

$ git rebase -i A~1 

y squash Fixa en A, dan como resultado:

A'-B-C 

¿Hay un comando para hacer algo como:

A-B-C + (index with fix for A) 

$ git commit -supperdupper A 

Resultado:

A'-B-C 
+1

¿Por qué un requisito tan extraño que fixA tiene que fusionarse en A? –

+9

porque debería haber estado en A en primer lugar. – elmarco

+4

Hago lo mismo; No estoy seguro de por qué la gente piensa que es extraño. Si intentas organizar commits en piezas pequeñas y lógicamente agrupadas, entonces es natural preparar varios commit inéditos a la vez. (Puede que no sepa si realmente ha terminado con A hasta que termine C). – andy

Respuesta

19

Si solo está buscando la solución más fácil para solucionar las confirmaciones anteriores, ¡lea la pregunta! Lo explica todo. Pero desde Elmarco estaba pidiendo una manera hábil, aquí vamos:

A partir de Git 1.7.0, hay una opción para --autosquashrebase, que hace lo que quiere. También están las opciones --fixup y --squash para commit para facilitar las cosas. Con algunos aliasing, probablemente incluso puedas obtener todo en un solo comando.

me gustaría sugerir la actualización a la nueva Git para obtener la máxima genialidad:

git/Documentation/RelNotes $ grep -i -A1 autosquash\\\|fixup * 
1.7.0.txt: * "git rebase -i" learned new action "fixup" that squashes the change 
1.7.0.txt- but does not affect existing log message. 
-- 
1.7.0.txt: * "git rebase -i" also learned --autosquash option that is useful 
1.7.0.txt: together with the new "fixup" action. 
1.7.0.txt- 
-- 
1.7.3.txt: * "git rebase -i" peeks into rebase.autosquash configuration and acts as 
1.7.3.txt: if you gave --autosquash from the command line. 
1.7.3.txt- 
-- 
1.7.4.txt: * "git commit" learned --fixup and --squash options to help later invocation 
1.7.4.txt- of the interactive rebase. 
-- 
1.7.4.txt: * "git rebase --autosquash" can use SHA-1 object names to name which 
1.7.4.txt: commit to fix up (e.g. "fixup! e83c5163"). 
1.7.4.txt- 
+1

Buen ejemplo: http://technosorcery.net/blog/2010/02/07/fun-with-the-upcoming-1-7-release-of-git-rebase---interactive---autosquash/ –

+0

This es también un blog relevante http://netsplit.com/2012/02/06/git-smash/ – elmarco

+0

En un solo comando: http://stackoverflow.com/a/13671819/1456578 – Deiwin

0

Lo que estás haciendo es peligroso si compartes la rama en la que estás haciendo cambios con otras personas. En su caso, está reescribiendo confirme A y vuelva a basar B y C en la parte superior de la nueva A, que es un objeto completamente nuevo. Cualquiera que ya haya sacado la antigua A en sus repositorios podría terminar corrompiendo su repositorio ya que la historia en su repositorio habrá cambiado "mágicamente". Su git no tendría forma de saber que la historia ha sido reescrita.

Debido a esto, los desarrolladores de Git intencionalmente no han hecho esto fácil ya que deben conocer las consecuencias de realizar dicha operación.

+4

Soy consciente de las consecuencias, no quiero compartir esas confirmaciones. – elmarco

+2

De hecho, el git * del otro desarrollador * sabría * que la historia había cambiado. El formato de repositorio de Git garantiza que nunca se puede "corromper" un repositorio de esta manera. El problema es más sutil que eso y el idiota del destinatario puede arrojar un montón de conflictos de fusión innecesarios. –

+0

El problema se muestra aquí - http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#problems-with-rewriting-history –

2

Si desea aplastar las dos últimas confirmaciones entonces usted tiene que invocar

git rebase --interactive <3rd last commit> 

A continuación, deberá elegir el último commit y squash el penúltimo commit. No se puede aplastar la confirmación más alta de una historia.

1

I created some aliases para facilitar el uso de los comandos git commit --fixup y git commit --squash agregados en git 1.7. Añadir estos a su ~/.gitconfig:

[alias] 
    fixup = !sh -c 'REV=$(git rev-parse $1) && git commit --fixup [email protected] && git rebase -i --autosquash $REV^' - 
    squash = !sh -c 'REV=$(git rev-parse $1) && git commit --squash [email protected] && git rebase -i --autosquash $REV^' - 

Uso:

$ git commit -am 'bad commit' 
$ git commit -am 'good commit' 

$ git add .   # Stage changes to correct the bad commit 
$ git fixup HEAD^ # HEAD^ can be replaced by the SHA of the bad commit 

La mala cometer pueden ser varias comete espalda.

3

Mi flujo de trabajo git actual es tan --fixup/--squash intensiva, que escribí un nuevo comando git-fixup que se encarga de la mayor parte de los bits molestos automáticamente:

  • git fixup muestra los archivos modificados agrupadas en esa última se compromete a que toque los mismos archivos
  • git fixup -a compromete a todos esos cambios como --fixup cambios con sus correspondientes "padre" compromete
  • git fixup -r hace una automática git rebase --autosquash para toda la corrección comete

Una gran cantidad de cambios son tales que sólo los tres comandos anteriores son suficientes para hacer el trabajo, sin copiar y pegar de de cometer-ID o la lectura a través de la git log a encuentre los objetivos correctos --fixup.

Fuente: https://github.com/ohmu/git-crust

0

Creo que la raíz del problema es que git (y el control de versiones en general) obliga a pensar en términos de secuencias de cambios, sino un conjunto de cambios o característica de rama o lo que llamo una el grupo cohesivo de cambios relacionados en general no es lógicamente secuencial. El orden en que se escribió el código es incidental y no está necesariamente relacionado con el orden en que debe leerse.

No tengo una solución para eso, pero he escrito un Perl script para ayudar a automatizar el proceso de reescribir el historial. Es similar a la secuencia de comandos de Python de @MikaEloranta que no había visto cuando lo escribí.

y rebase --autosquash son geniales, pero no hacen lo suficiente. Cuando tengo una secuencia de commits A-B-C y escribo algunos cambios más en mi árbol de trabajo que pertenecen a uno o más commits existentes, tengo que mirar el historial manualmente, decidir qué cambios pertenecen a qué commits, ponerlos en escena y crear el fixup! confirma. Pero git ya tiene acceso a suficiente información para poder hacer todo eso por mí.

Para cada trozo en git diff la secuencia de comandos utiliza git blame para encontrar la confirmación que tocó por último las líneas relevantes, y pide git commit --fixup escribir las correspondientes fixup! confirmaciones, esencialmente haciendo lo mismo que hacía manualmente antes.

Si la secuencia de comandos no puede resolver un trozo a una única confirmación inequívoca, lo informará como un trozo fallido y tendrá que recurrir al enfoque manual para esa. Si cambió una línea dos veces en dos confirmaciones separadas, la secuencia de comandos resolverá un cambio en esa línea a la última de esas confirmaciones, que podría no ser siempre la resolución correcta. En mi humilde opinión, en una rama de función de "forma normal", no debe cambiar una línea dos veces en dos confirmaciones diferentes, cada compromiso debe presentar la versión final de las líneas que toca, para ayudar al revisor (es). Sin embargo, puede suceder en una rama de corrección de errores, para crear un ejemplo, la línea foo(bar()); podría ser modificada por la confirmación A (renombre foo en fox) y confirme B (renombre bar en baz).

Si encuentra útil la secuencia de comandos, no dude en mejorar e iterar en ella y tal vez algún día obtengamos dicha función en git propiamente dicha. Me encantaría ver una herramienta que pueda entender cómo debe resolverse un conflicto de fusión cuando ha sido introducido por una base de datos interactiva.