Estoy fallando en entender como usar git-rebase
, y considero el siguiente ejemplo.
Vamos a empezar un repositorio en ~/tmp/repo
:
$ git init
Luego agrega un archivo foo
$ echo "hello world" > foo
que luego se agrega y se compromete:
$ git add foo
$ git commit -m "Added foo"
A continuación, comencé un repositorio remoto. En ~/tmp/bare.git
corrí
$ git init --bare
Para enlazar repo
a bare.git
corrí
$ git remote add origin ../bare.git/
$ git push --set-upstream origin master
A continuación, vamos a la rama, agregue un archivo y establezca un flujo ascendente para la nueva rama b1
:
$ git checkout -b b1
$ echo "bar" > foo2
$ git add foo2
$ git commit -m "add foo2 in b1"
$ git push --set-upstream origin b1
Ahora es el momento de volver a master
y cambiar algo allí:
$ echo "change foo" > foo
$ git commit -a -m "changed foo in master"
$ git push
En este punto en master
el archivo foo
Contiene cambiado foo , mientras en b1
aún es Hola Mundo . Finalmente, quiero sincronizar. b1
con el progreso realizado en master
.
$ git checkout b1
$ git fetch origin
$ git rebase origin/master
En este punto git st
devoluciones:
# On branch b1
# Your branch and 'origin/b1' have diverged,
# and have 2 and 1 different commit each, respectively.
# (use "git pull" to merge the remote branch into yours)
#
nothing to commit, working directory clean
En este punto el contenido de foo
en la rama b1
es cambiar foo también. Entonces, ¿qué significa esta advertencia? Esperaba que hiciera una git push
, Git sugiere hacer git pull
... De acuerdo a esta respuesta , esto es más o menos eso, y en su comentario @FrerichRaabe dice explícitamente que no necesito hacer un tirón. ¿Que está pasando aqui? ¿Cuál es el peligro, cómo se debe proceder? ¿Cómo debe mantenerse la historia consistente? ¿Cuál es la interacción entre el caso descrito anteriormente y la siguiente cita:
No vuelva a marcar las confirmaciones que haya enviado a un repositorio público.
tomado de libro pro git .
Supongo que está relacionado de alguna manera, y si no me encantaría saber por qué. ¿Cuál es la relación entre el escenario anterior y el procedimiento que describí? en este post .
fuente
git st
Da esa salida porque Git sabe que tu local.b1
rama está siguiendoorigin/b1
, así que eso es lo que quieres reajustar. Tu corresgit rebase origin/master
Sin embargo, por lo que ha vuelto a basar ("repetido") sub1
cometer encima deorigin/master
.origin/master
ymaster
se actualizan, debería rebaseorigin/b1
enorigin/master
y luego hacergit pull
cuandob1
¿Se verifica para extraer el rebase al repositorio local?git pull
y nunca rebasa una rama remota (por ejemplo,origin/master
) en cualquier otra cosa.origin/b1
yb1
no son lo mismo. Esto es bastante obvio, pero ¿cuál es la forma correcta de solucionarlo? ¿O arreglarlo significa desordenar la historia como se explicó @heavyd?Respuestas:
La razón por la que no desea volver a generar las confirmaciones que ha enviado a un repositorio público es porque
git-rebase
El comando cambia la historia.Ahora, ¿qué significa eso y por qué es malo? Primero, sugeriría leer esta sección del libro git. A partir de eso, aprenderá que las confirmaciones consisten en un puntero a un objeto de árbol (instantánea de los archivos) y un puntero a la confirmación principal. Ahora, cuando "cambia el historial" volviendo a basar las confirmaciones sobre las nuevas confirmaciones, está cambiando el puntero principal de las confirmaciones que ya ha realizado, lo que a su vez cambia el ID de sus confirmaciones.
La razón por la que esto es malo es que si comparte sus compromisos públicamente, y otros comienzan un trabajo adicional basado en esos compromisos, luego realiza un cambio en esos compromisos, sus árboles ya no están sincronizados.
Todo esto se puede ver emitiendo
git-log
Comandos mientras realizas tu ejemplo. Corrí estos justo antes de ejecutar el comando rebase:Y ahora después de realizar la rebase,
origin/master
yorigin/b1
son lo mismo, perob1
es ahora:Notará que la confirmación "foo2 agregado en b1" tiene una ID diferente a la de los comandos de registro anteriores. Si confirma este cambio en su repositorio público, ahora tiene dos confirmaciones que tienen el mismo trabajo realizado en ellos y eso causa problemas.
Ahora suponga que, en lugar de volver a basar b1 en la parte superior del maestro, simplemente fusionó el maestro en b1, su registro se vería así:
Notará la confirmación adicional que representa la combinación de las dos confirmaciones anteriores. Esta historia ahora puede ser compartida y todos serán felices.
git-log --graph
También puede ayudar a arrojar algo de luz adicional sobre lo que está sucediendo.fuente
origin/b1
solo lo uso yo mismo - asumiendo que es una especie de respaldo deb1
. ¿Qué efecto tiene este supuesto sobre la situación? ¿Tiene sentido en este caso hacer?git push --force
¿O algo similar justo después de la rebase?git merge master
cuando elfoo
La sucursal está desprotegida. De nuevo, pruébalo por ti mismo y usagit-log
para ver que esta pasandomaster
Se considera una rama estable mientras quefoo
(o cualquier otra rama) no es estable. La fusión de estable en inestable es indeseable, por lo tanto, el trabajo adicional. Estoy tratando de averiguar si hay accesos directos o no.Tarde en la fiesta, pero aquí está la respuesta para la posteridad:
git rebase
está destinado a ser utilizado localmente. Reescribe el historial, lo que permite una "línea principal" muy agradable, pero es peligroso en un entorno multiusuario.Si:
Entonces eso podría tiene sentido hacer esto por forzando La historia a reescribir. Haga su rebase y luego:
Si alguna de estas suposiciones no se cumplió, puede vivir para lamentar esta acción :-)
Lee más en esta entrada de blog
fuente