¿Es peligroso git-svn dcommit después de fusionarse en git?


Mi motivación para probar git-svn es la fusión y ramificación sin esfuerzo. Entonces me di cuenta de que man git-svn(1) dice:

NO se recomienda ejecutar git-merge o git-pull en una rama que planee para el compromiso de. Subversion no representa fusiones en ninguna razonable o útil; por lo que los usuarios que usan Subversion no pueden ver ninguna fusiones que has hecho. Además, si fusiona o extrae desde un git rama que es un espejo de una rama SVN, dcommit puede comprometerse a la Equivocada Sucursal.

¿Significa esto que no puedo crear una rama local desde svn/trunk (o una rama), hackear, fusionar de nuevo en svn/trunk, y luego dcommit? Entiendo que los usuarios de svn verán el mismo desorden que se fusiona en svn pre 1.5.x siempre ha sido, pero hay algún otro inconveniente? Esa última frase también me preocupa. ¿La gente hace rutinariamente este tipo de cosas?

Author: code_dredd, 2008-10-10

6 answers

En realidad, encontré una manera aún mejor con la opción --no-ff en git merge. Toda esta técnica de squash que utilicé antes ya no es necesaria.

Mi nuevo flujo de trabajo es ahora el siguiente:

  • Tengo una rama "master" que es la única rama desde la que me comprometo y que clona el repositorio SVN (-s asumo que tienes un diseño SVN estándar en el repositorio trunk/, branches/, y tags/):

    git svn clone [-s] <svn-url>
    
  • Trabajo en una rama local "work" (-b crea la rama "trabajo")

    git checkout -b work
    
  • Commit localmente en la rama "work" (-s para firmar tu mensaje de commit). En la secuela, asumo que hiciste 3 commits locales

    ...
    (work)$> git commit -s -m "msg 1"
    ...
    (work)$> git commit -s -m "msg 2"
    ...
    (work)$> git commit -s -m "msg 3"
    

Ahora desea confirmar en el servidor SVN

  • [Eventualmente] guarde las modificaciones que no desea ver confirmadas en el servidor SVN (a menudo comentó algún código en el archivo principal solo porque desea acelerar la compilación y centrarse en un determinado característica)

    (work)$> git stash
    
  • Rebase la rama master con el repositorio SVN (para actualizar desde el servidor SVN)

    (work)$> git checkout master
    (master)$> git svn rebase
    
  • Vuelva a la rama de trabajo y rebase con master

    (master)$> git checkout work
    (work)$> git rebase master
    
  • Asegúrese de que todo esté bien usando, por ejemplo:

    (work)$> git log --graph --oneline --decorate
    
  • Ahora es el momento de combinar las tres confirmaciones de la rama "work" en "master" usando esta maravillosa opción --no-ff

    (work)$> git checkout master
    (master)$> git merge --no-ff work
    
  • Puede notar el estado de la logs:

    (master)$> git log --graph --oneline --decorate
    * 56a779b (work, master) Merge branch 'work'
    |\  
    | * af6f7ae msg 3
    | * 8750643 msg 2
    | * 08464ae msg 1
    |/  
    * 21e20fa (git-svn) last svn commit
    
  • Ahora probablemente quieras editar (amend) el último commit para tus SVN dudes (de lo contrario solo verán un solo commit con el mensaje "Merge branch 'work'"

    (master)$> git commit --amend
    
  • Finalmente confirmar en el servidor SVN

    (master)$> git svn dcommit
    
  • Vuelve al trabajo y eventualmente recupera tus archivos guardados:

    (master)$> git checkout work
    (work)$> git stash pop
    
 171
Author: Sebastien Varrette,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-31 12:35:37

Crear ramas locales es definitivamente posible con git-svn. Siempre y cuando solo estés usando ramas locales para ti mismo, y no intentes usar git para fusionar entre ramas svn upstream, deberías estar bien.

Tengo una rama "master" que uso para rastrear el servidor svn. Esta es la única rama de la que me comprometo. Si estoy haciendo algún trabajo, creo una rama temática y trabajo en ella. Cuando quiero confirmarlo, hago lo siguiente:

  1. Confírmalo todo al tema branch
  2. git svn rebase (resuelve cualquier conflicto entre tu trabajo y svn)
  3. git checkout master
  4. git svn rebase (esto hace que el siguiente paso sea una fusión rápida, vea los comentarios de Aaron a continuación)
  5. git merge topic_branch
  6. resolver cualquier conflicto de fusión (no debería haber ninguno en este punto)
  7. git svn dcommit

También tengo otra situación en la que necesito mantener algunos cambios locales (para la depuración) que nunca debe ser empujado hasta svn. Para eso, tengo la rama maestra anterior, pero también una rama llamada "trabajo"donde normalmente trabajo. Las ramas temáticas se ramifican del trabajo. Cuando quiero confirmar el trabajo allí, compruebo master y uso cherry-pick para seleccionar las confirmaciones de la rama de trabajo que quiero confirmar en svn. Esto se debe a que quiero evitar cometer las tres confirmaciones de cambios locales. Entonces, me comprometo desde la rama principal y rebase todo.

Vale la pena ejecutar git svn dcommit -n primero para asegurarse de que está a punto de cometer exactamente lo que pretende cometer. A diferencia de git, reescribir la historia en svn es difícil!

Creo que debe haber una mejor manera de fusionar el cambio en una rama temática mientras se omiten esas confirmaciones de cambio locales que usando cherry-pick, por lo que si alguien tiene alguna idea sería bienvenido.

 49
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-22 21:32:20

Solución simple: Eliminar la rama 'work' después de fusionar

Respuesta corta: Puedes usar git como quieras (ver a continuación un flujo de trabajo simple), incluyendo merge. Solo asegúrate de seguir cada ' git merge work' con ' git branch-d work' para eliminar la rama de trabajo temporal.

Explicación de antecedentes: El problema de merge/dcommit es que cada vez que 'git svn dcommit' una rama, el historial de merge de esa rama es 'aplanado': git se olvida de todas las operaciones de fusión que entraron en esta rama: Solo se conserva el contenido del archivo, pero se pierde el hecho de que este contenido (parcialmente) provenga de una rama específica. Ver: ¿Por qué git svn dcommit pierde el historial de confirmaciones de fusión para las ramas locales?

(Nota: No hay mucho que git-svn podría hacer al respecto: svn simplemente no entiende las fusiones de git mucho más poderosas. Por lo tanto, dentro del repositorio svn esta información de fusión no puede ser representado de cualquier manera.)

Pero este es el problema completo. Si eliminas la rama 'work' después de que se haya fusionado en la 'master branch', entonces tu repositorio git está 100% limpio y se ve exactamente igual que tu repositorio svn.

Mi flujo de trabajo: Por supuesto, primero cloné el repositorio svn remoto en un repositorio git local (esto puede llevar algún tiempo):

$> git svn clone <svn-repository-url> <local-directory>

Todo el trabajo entonces sucede dentro del "local-directory". Cada vez que necesito recibir actualizaciones desde el servidor (como 'svn update'), lo hago:

$> git checkout master
$> git svn rebase

Hago todo mi trabajo de desarrollo en una rama separada 'trabajo' que se crea de esta manera:

$> git checkout -b work

Por supuesto, puede crear tantas ramas para su trabajo como desee y fusionar y rebase entre ellas como desee (simplemente elimínelas cuando haya terminado con ellas, como se explica a continuación). En mi trabajo normal, me comprometo con mucha frecuencia:

$> git commit -am '-- finished a little piece of work'

El siguiente paso (git rebase-i) es opcional - - - es solo limpiar el historial antes de archivarlo en svn: Una vez que llegué a una piedra de milla estable que quiero compartir con otros, reescribo la historia de esta rama de 'trabajo' y limpio los mensajes de confirmación (otros desarrolladores no necesitan ver todos los pequeños pasos y errores que cometí en el camino --- solo el resultado). Para esto, lo hago

$> git log

Y copie el hash sha-1 de la última confirmación que está activa en el repositorio svn (como se indica por un git-svn-id). Entonces llamo

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

Solo pega sha-1 hash de nuestro último svn commit en lugar del mío. Es posible que desee leer la documentación con 'git help rebase' para obtener los detalles. En resumen: este comando primero abre un editor que presenta tus commits - - - - solo cambia 'pick' a 'squash' para todos aquellos commits que quieras squash con commits anteriores. Por supuesto, la primera línea debe permanecer como una 'selección'. De esta manera, puedes condensar tus muchos commits pequeños en una o más unidades significativas. Guarde y salga del editor. Usted recibirá otro editor pidiéndole que reescriba los mensajes del registro de confirmación.

En resumen: Después de terminar 'code hacking', masajeo mi rama 'work' hasta que se vea cómo quiero presentarla a los otros programadores (o cómo quiero ver el trabajo en unas pocas semanas cuando navegue por el historial).

Para enviar los cambios al repositorio svn, hago:

$> git checkout master
$> git svn rebase

Ahora estamos de vuelta en la antigua rama 'master' actualizada con todos los cambios que ocurrieron mientras tanto en el repositorio svn (sus nuevos cambios están ocultos en la rama "trabajo").

Si hay cambios que pueden entrar en conflicto con sus nuevos cambios de 'trabajo', tiene que resolverlos localmente antes de que pueda empujar su nuevo trabajo (ver detalles más adelante). Entonces, podemos empujar nuestros cambios a svn:

$> git checkout master
$> git merge work        # (1) merge your 'work' into 'master'
$> git branch -d work    # (2) remove the work branch immediately after merging
$> git svn dcommit       # (3) push your changes to the svn repository

Nota 1: El comando 'git branch-d work' es bastante seguro: solo te permite eliminar ramas que ya no necesitas (porque ya están fusionadas en tu rama actual). Si ejecuta este comando por error antes de fusionar su si trabaja con la rama 'master', recibirá un mensaje de error.

Nota 2: Asegúrese de eliminar su rama con 'git branch-d work' entre merging y dcommit: Si intenta eliminar la rama después de dcommit, recibe un mensaje de error: Cuando hace 'git svn dcommit', git olvida que su rama se ha fusionado con 'master'. Tienes que eliminarlo con 'git branch-D work' que no hace la comprobación de seguridad.

Ahora, inmediatamente creo una nueva rama' work ' para evitar hackear accidentalmente la rama 'master':

$> git checkout -b work
$> git branch            # show my branches:
  master
* work

Integración de su' trabajo ' con cambios en svn: Esto es lo que hago cuando 'git svn rebase' revela que otros cambiaron el repositorio svn mientras yo estaba trabajando en mi rama 'work':

$> git checkout master
$> git svn rebase              # 'svn pull' changes
$> git checkout work           # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master            # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed

$> git checkout master         # try again to push my changes
$> git svn rebase              # hopefully no further changes to merge
$> git merge integration       # (1) merge your work with theirs
$> git branch -d work          # (2) remove branches that are merged
$> git branch -d integration   # (2) remove branches that are merged
$> git svn dcommit             # (3) push your changes to the svn repository

Existen soluciones más potentes: El flujo de trabajo presentado es simplista: Utiliza los poderes de git solo dentro de cada ronda de 'update / hack / dcommit' - - - pero deja el historial del proyecto a largo plazo tan lineal como el svn repositorio. Esto está bien si solo quieres comenzar a usar git merges en pequeños primeros pasos en un proyecto svn heredado.

Cuando se familiarice con la fusión de git, siéntase libre de explorar otros flujos de trabajo: Si sabe lo que está haciendo, puede mezclar las fusiones de git con las fusiones de svn (Usando git-svn (o similar) solo para ayudar con la fusión de svn?)

 33
Author: Yaakov Belch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:32:11

Greg Hewgill respuesta en la parte superior no es seguro! Si alguna nueva confirmación aparece en el tronco entre los dos "git svn rebase", la fusión no será rápida.

Se puede asegurar usando la bandera "only ff-only" en git-merge, pero normalmente no corro "git svn rebase" en la rama, solo "git rebase master" en ella (asumiendo que es solo una rama local). Luego, se garantiza que un "git merge thebranch" será rápido.

 8
Author: Marius K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-16 11:49:33

Una forma segura de fusionar ramas svn en git es usar git merge squash squash. Esto creará un solo commit y se detendrá para que agregues un mensaje.

Digamos que tienes un tema svn branch, llamado svn-branch.

git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch

En este punto tiene todos los cambios de la rama svn aplastados en una confirmación esperando en el índice

git commit
 6
Author: luntain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-06 16:30:11

Rebase la rama git local en la rama git maestra luego dcommit y de esa manera parece que hiciste todas esas confirmaciones en secuencia para que la gente de svn pueda verla linealmente como están acostumbrados. Así que asumiendo que tienes una rama local llamada topic podrías hacer

git rebase master topic

Que luego reproducirá tus commits sobre la rama master listo para que puedas dcommit

 5
Author: JoeyJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-11 09:12:22