2009-02-18 21 views
68

Tengo una rama que debería estar disponible para otros colaboradores y que debe estar constantemente actualizada con el maestro.git rebase y git push: avance rápido, ¿por qué usar?

Desafortunadamente, cada vez que hago 'git rebase' y luego trato de presionar, se produce un mensaje de 'no avance rápido' y aborto de empujar. La única forma de presionar aquí es usar --force. ¿Eso significa que debería usar 'git merge' en lugar de volver a establecer una base de datos si mi sucursal se hizo pública y otros están trabajando en ello?

Respuesta

99

Algunas notas sobre cómo git obras (no técnico):

Cuando se rebase, git toma las confirmaciones de que se trate, y "renueva su" en la parte superior de un historial limpio. Esto es para evitar que la historia de la muestra:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge 
Commit SHA1: aaaa -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg 

Después de un rebase, puede tener este aspecto (o similar):

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

La cuestión es que el nuevo commit que está intentando empujar a cabo hay NO es un descendiente de la confirmación en la punta de la rama a la que está presionando.

Ahora, sabes que la misma información está en las confirmaciones, pero git se está responsabilizando no solo sobrescribiendo esas confirmaciones (bbbb-gggg en el ejemplo anterior).


compartido Repo Modelo

Si está utilizando un repositorio compartido, entonces este tipo de cosas pueden obtener poderosa confuso. Déjame explicar por qué. Digamos que otro desarrollador bajó la rama, y ​​han confirmado aaaa -> gggg en su rama. Luego hacen un commit iiii

En el mientras tanto, se restablecen y forzado un empujón, haciendo que el árbol para tener este aspecto:

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

Cuando el otro desarrollador trata de empujar, se consigue un " mensaje de "no avance rápido". Cuando lo hace una fusión, a continuación, ambas historias se vuelven a vincular entre sí, y que terminan con un lío

Algo como esto (desordenado):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg -> iiii -> jjjj 

En otras palabras, si los demás están tirando y empujando , es mejor que te quedes con git merge, o EVITAR EMPUJAR hasta después de la rebase (y solo rebase tu trabajo).


visible para el público Modelo Repositorio

Tal vez usted está utilizando un modelo diferente (más gittish) en el que sólo quiere que la gente sea capaz de tirar de su cesión temporal. En este caso, git push --force no es tan malo, porque pueden lidiar con mantenerse al día. Pueden volver a establecer la base sus cambios para estar al tanto de los cambios antes de darle sus parches.Evita que su repositorio se ensucie.

Sin embargo, puede haber una manera mejor para usted. git push --mirror

From http://www.kernel.org/pub/software/scm/git/docs/git-push.html

lugar de nombrar cada árbitro empujar, especifica que todos los árbitros bajo $ GIT_DIR/refs/(que incluye, pero es no limitado a refs/heads/, refs/remotes /, y refs/tags /) be reflejado en el repositorio remoto. Refs locales recién creados serán empujados al extremo remoto, localmente refs actualizados se actualizarán en el extremo remoto, y los refs eliminados se eliminarán del extremo remoto. Este es el valor predeterminado si se configura la opción opción remote..mirror.


Una de las mejores cosas de git es que es muy flexible y permite muchos tipos diferentes de flujos de trabajo. Pero su verdadera fuerza reside en el hecho de que es un modelo distribuido, por lo que creo que la mayor parte del ROI se puede cosechar al usarlo de esa manera.

+7

Err, en realidad, fusionar crea confusiones de fusión, que no necesitan aclarar. En cambio, es genial 'get git, git rebase origin/master', resuelve todos tus conflictos locales con la rama maestra (centralizada) y luego realiza commits puros que solo avanzan. 'git pull --rebase' tiene un flujo de trabajo similar. Esta es una opción poderosa, pero debes tener cuidado con ella, ya que si reescribes las cosas incorrectas puedes reescribir las confirmaciones que ya están en el origen/maestro. P.ej. no vuelva a establecer la base de otras ramas a menos que se vuelvan a establecer en el origen/maestro actual primero. – Kzqai

+0

De acuerdo, las asignaciones de combinación deben evitarse al hacer un jalón. Sin embargo, creo que son buenos para conservar cuando se fusiona intencionalmente una rama de características en maestra. – ndbroadbent

+3

Me gusta la explicación de por qué hay un problema, empujando una rama rebasada. Pero no estoy seguro de lo que --mirror logra. Leer la descripción - "especifica que * todos los refs * se reflejarán" - me molesta. No quiero * todas las referencias * reflejadas, solo una rama. :) ¿Nombrar una rama solo reflejará esa? No está claro para mí de los documentos de Git. –

2

No, rebase es perfectamente legal con repositorios públicos e incluso puede ser conveniente mantener el historial fluido. Solo tenga en cuenta que no debe usar rebase para reescribir el historial de confirmaciones publicadas remotamente. Es decir, la rebase solo se puede aplicar a la suya, local, confirma que nunca se ha publicado. Usas rebase para colocar tus commits encima de ellos cuando los recuperas y luego, quizás, los ajustes allí. Otra razón por la que puede recibir este tipo de mensaje es porque la rama que está presionando se actualizó y necesita sincronizar: busque y vuelva a establecer sus compromisos sobre lo que haya obtenido.