2008-12-12 12 views
42

He aquí un ejemplo:¿Cómo uso 'git rebase -i' para volver a establecer la base de todos los cambios en una rama?

>git status 
# On branch master 
nothing to commit (working directory clean) 
>git checkout -b test-branch 
>vi test.c 
>git add test.c 
>git commit -m "modified test.c" 
>vi README 
>git add README 
>git commit -m "modified README" 

Ahora quiero hacer un 'git rebase -i' que me permita rebase todas las confirmaciones de esta rama. ¿Hay algo como 'git rebase -i HEAD~MASTER' o similar? Me imagino que podría hacer 'git rebase -i HEAD~2', pero realmente no quiero tener que contar cuántas confirmaciones se han realizado. También podría hacer 'git rebase -i sha1' pero no quiero peinarlo a través del registro de git para encontrar el primer commit sha1. ¿Algunas ideas?

+1

Por favor titular su pregunta un poco mejor. Tal vez mencione que desea hacer una rebase interactiva para todos los cambios en una rama. Preferentemente en forma de pregunta (aunque no siempre es posible). – Dustin

+0

¿Desea volver a establecer una base en un 'maestro' modificado o simplemente editar las confirmaciones que acaba de realizar en' test-branch'? – DylanYoung

Respuesta

32

¿Has probado: git rebase -i master?

+0

Acabo de probar esto en mi repositorio de muestras y funciona. – Otto

+14

Esto falla si el maestro está por delante de la base de combinación actual en su sucursal. –

+3

El problema con 'git rebase -i master' es que puede tener conflictos de fusión que no necesariamente desea tratar en este momento, o puede solucionar un conflicto en una confirmación, solo para arreglarlo nuevamente en otra confirmación durante el curso de la rebase. He agregado una respuesta que ofrece una alternativa a esto y una alternativa para especificar la confirmación exacta o la cantidad de confirmaciones de las que desea volver a establecer la base. –

17

Use gitk (* nix), o gitx (OS X) o similar en otras plataformas, y observe la confirmación que fue la raíz de su rama. A continuación, ejecute:

git rebase -i <the SHA hash of the root commit> 

Por ejemplo, tengo un repositorio que inspeccioné usando gitx:

gitx screencap http://img.skitch.com/20081213-mq7qpp5nhceksdhfx14rerjgyx.jpg

Ahora que sé que el hash de la raíz que se puede ejecutar esto:

git rebase -i 38965ed29d89a4136e47b688ca10b522b6bc335f 

Y mi editor aparece con esto y puedo reorganizar/aplastar/lo que quiera.

pick 50b2cff File 1 changes. 
pick 345df08 File 2 changes. 
pick 9894931 File 3 changes. 
pick 9a62b92 File 4 changes. 
pick 640b1f8 File 5 changes. 
pick 1c437f7 File 6 changes. 
pick b014597 File 7 changes. 
pick b1f52bc File 8 changes. 
pick 40ae0fc File 9 changes. 

# Rebase 38965ed..40ae0fc onto 38965ed 
# 
# Commands: 
# pick = use commit 
# edit = use commit, but stop for amending 
# squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST. 
# However, if you remove everything, the rebase will be aborted. 
# 

estoy seguro de que hay alguna forma mágica para convencer a git para averiguar la raíz del árbol de forma automática, pero no sé lo que es.

EDIT: Esa magia es la siguiente:

git log master..other_feature | cat 

que le mostrará todas las confirmaciones en esa rama, y ​​las tuberías a gato se desactivará el localizador de manera que vea la primera inmediatamente envían.

EDIT: la combinación de lo anterior da una solución totalmente automatizada:

git rebase -i `git log master..other_feature --pretty=format:"%h" | tail -n 1`~ 
+4

-1 OP dijo que no quería rastrear los registros –

+0

'| cat' parece un uso inútil del gato cuando puedes usar 'git --no-pager'. –

+0

@MatthieuMoy --no-pager probablemente no estaba en la versión que estaba usando en diciembre de 2008. Esa opción no había aterrizado en el código base hasta julio de 2008. https://github.com/git/git/commit/ 4e10738a9392ad285aca7d3a19e6775d6b7b513e – Otto

44

Ok, estoy Asumiendo la rama se llama "característica" y se ramificado de "maestro".

Hay este pequeño comando git llamado combinación-base. Se necesitan dos commits y te da el primer ancestro común de ambos. Así que ...

git merge-base feature master 

... le dará el primer antepasado común de estas dos confirmaciones. Adivinar lo que sucede cuando se pasa de que se comprometan a git rebase -i, como ...

git rebase -i `git merge-base feature master` 

interactivo rebase desde el primer antepasado común de ambos principal y característica de la rama. ¡Beneficio! ;)

+1

Aunque es feo, ¿no hay azúcar sintáctico a la mano? –

+8

Eso es bonito comparado con muchas soluciones de git :). – studgeek

+5

Sugeriría usar 'git merge-base master HEAD' que siempre debería funcionar para la rama actual sin escribir el nombre de la rama actual. Alias ​​este comando y tienes tu buen comando short git. – jayeff

1

Una solución general (si no conoce el nombre de la rama aguas arriba) es:

git rebase -i @{upstream} 

Tenga en cuenta que si su corriente arriba (probablemente una rama de seguimiento) ha actualizado desde la última vez rebasada, tirarás nuevas confirmaciones de la corriente ascendente.Si no desea obtener nuevas confirmaciones, use

git rebase -i `git merge-base --all HEAD @{upstream}` 

pero eso es un poco engorroso.

+0

He visto sugerencias de que la diferencia simétrica HEAD ... master (que produce la base de combinación como el tercer sha negado) se puede usar en git rebase, pero no sé cómo. –

0
git rebase -i --onto @{u}... @{u} 

rebase interactivo a partir del punto de fusión única de la cabeza y su aguas arriba incluyendo todos los envíos en la cabeza de que no están en su contra la corriente.

En otras palabras, exactamente lo que quiere.

+0

Pero si '@ {u}' está configurado, entonces puede usar el argumento 'git rebase', vea mi respuesta. –

4

Desde Git v1.7.10, puede simplemente ejecutar git rebase sin argumentos, y encontrará el punto de horquilla y rebase sus cambios locales en la rama ascendente.

Debe haber configurado la rama ascendente para que esto funcione (es decir, git pull sin argumento debería funcionar).

Para más detalles, consulte la documentación de git rebase:

Si no se especifica, el sentido ascendente configurados en opciones branch..remote y branch..merge será utilizado (ver git-config [ 1] para más detalles) y se asume la opción --fork-point. Si no está actualmente en ninguna rama o si la rama actual no tiene configurada en sentido ascendente, la rebase abortará.

38

El problema con todas las soluciones proporcionadas es que no permiten volver a establecer la base de datos desde la primera confirmación. Si el hash primero comprometerse es XYZ y lo hace:

git rebase -i XYZ 

Sólo se rebase a partir de la segunda comprometerse.

Si desea reajustar desde el primer comprometerse haces:

git rebase -i --root 
+5

Creo que esta es la respuesta correcta. –

+12

Pero "--root" rebases desde el primer commit * ever * en lugar del primer commit en la rama que es lo que el OP está pidiendo –

4

El problema con el cambio de base de una rama diferente

El problema con git rebase -i master es que es posible que tenga conflictos de combinación que se no necesariamente desea tratar con esto en este momento, o puede solucionar un conflicto en una confirmación, solo para corregirlo nuevamente en otra confirmación durante el transcurso de la rebase.

El problema con el cambio de base de un conocido cometer

Todo el problema aquí es que usted tiene que saber cuales confirmar tiene que referirse, ya sea por su SHA, o la cabeza ~ x, etc. Esto es solo una pequeña molestia pero es una molestia.

La mejor manera

Si por el contrario quiere reajustar todos los compromete en su rama actual, ya que la más reciente cometer compartía con su rama padre, usted puede agregar la siguiente alias.gitconfig:

rbi = !sh -c \"git rebase -i `git merge-base $1 HEAD`\" - 

Uso

git rbi parentBranch 

Cómo funciona

Este alias es solamente un guión, es decir, utilizando un argumento que se refiere a la rama principal. Ese argumento se pasa al git merge-base para determinar la confirmación compartida más reciente entre esa rama y la rama actual.

+0

No estoy seguro de que esta respuesta tenga mucho sentido con la topología dada. La base de fusión aquí será 'master' en el momento en que se creó' test-branch' (digamos '3hgn45'). Entonces esta rebase en realidad no hace nada. Dice rebase esta rama de (pero no incluye) '3hgn45' a (e incluyendo)' HEAD' en '3hgn45'. Pero tal vez estoy malinterpretando tu sugerencia ... – DylanYoung

+0

EDIT: lo entiendo; la pregunta de OP simplemente no estaba clara para mí. Podría considerar agregar una advertencia de que esto no mantendrá los cambios de 'master' (es decir, no se trata de una actualización real, ya que mantiene la misma base, solo edita algunas confirmaciones en la rama actual). – DylanYoung

+1

@DylanYoung - sí, mi comprensión de la pregunta del OP era que en realidad no querían volver a establecer la base de 'master', sino que simplemente aplastaban todos los commits en uno, ya que divergían de' master'. –

Cuestiones relacionadas