Mi motivación para probar git-svn es la fusión y ramificación sin esfuerzo. Entonces noté que el hombre git-svn (1) dice:
NO se recomienda ejecutar git-merge o git-pull en una rama desde la que planee enviar. Subversion no representa fusiones de ninguna manera razonable o útil; por lo que los usuarios que usan Subversion no pueden ver ninguna fusión que hayas realizado. Además, si se fusiona o extrae de una rama git que es un espejo de una rama SVN, dcommit puede comprometerse con la rama incorrecta.
¿Esto significa que no puedo crear una rama local desde svn / trunk (o una rama), cortar, fusionar de nuevo en svn / trunk, y luego dcommit? Entiendo que los usuarios de svn verán el mismo desorden que las fusiones en svn pre 1.5.x siempre han sido, pero ¿hay otros inconvenientes? Esa última oración también me preocupa. ¿Las personas hacen rutinariamente este tipo de cosas?
--mergeinfo=<mergeinfo>
opción que puede transferir información de fusión al SVN. Sin embargo, no estoy seguro de cómo debería usarse.Respuestas:
En realidad, encontré una forma aún mejor con la
--no-ff
opción de git merge. Toda esta técnica de squash que usé antes ya no es necesaria.Mi nuevo flujo de trabajo ahora es el siguiente:
Tengo una rama "master", que es la única rama que dcommit de que el clon y el repositorio SVN (
-s
se supone que tiene un diseño estándar de SVN en el repositoriotrunk/
,branches/
ytags/
):Trabajo en una rama local "trabajo" (
-b
crea la rama "trabajo")comprometerse localmente en la rama "trabajo" (
-s
para cerrar su mensaje de confirmación). En la secuela, supongo que hiciste 3 confirmaciones localesAhora quieres comprometerte con el servidor SVN
[Eventualmente] guarde las modificaciones que no desea ver confirmadas en el servidor SVN (a menudo comentaba algún código en el archivo principal solo porque desea acelerar la compilación y centrarse en una característica dada)
Reubique la rama maestra con el repositorio SVN (para actualizar desde el servidor SVN)
volver a la rama de trabajo y rebase con master
Asegúrese de que todo esté bien usando, por ejemplo:
Ahora es el momento de fusionar los tres commits de la rama "trabajo" en "master" usando esta maravillosa
--no-ff
opciónPuede observar el estado de los registros:
Ahora probablemente desee editar (
amend
) la última confirmación para sus tipos SVN (de lo contrario, solo verán una única confirmación con el mensaje "Combinar rama 'trabajo'"Finalmente comprometerse en el servidor SVN
Vuelva al trabajo y finalmente recupere sus archivos escondidos:
fuente
--no-ff
opción, está creando explícitamente un commit de fusión (un commit con dos padres) en lugar de un avance rápido. Para garantizar que todas las confirmaciones en la rama de seguimiento de svn sean confirmaciones monoparentales, todas las fusiones deben adelantarse (--ff-only
puede ayudar con esto) o, si el tronco ha cambiado a sus espaldas, a--squash
, ¿verdad?git svn dcommit
reescribe el git commit que le das. Esto significa que usted pierde su otro padre, y ahora tu repositorio Git tiene ningún registro de que alguna vez combinada que se ramifican enmaster
. Esto también puede dejar su directorio de trabajo en un estado inconsistente.git merge --no-ff work -m "commit message"
lugar de tener ungit commit --amend
paso extraCrear sucursales 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 las ramas svn aguas arriba, deberías estar bien.
Tengo una rama "maestra" que uso para rastrear el servidor svn. Esta es la única rama de la que me comprometo. Si estoy haciendo algo de trabajo, creo una rama de tema y trabajo en ello. Cuando quiero cometerlo, hago lo siguiente:
También tengo otra situación en la que necesito mantener algunos cambios locales (para la depuración) que nunca se deben impulsar a 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 comprometer el trabajo allí, pago master y uso cherry-pick para elegir los commits de la rama de trabajo que quiero comprometer a svn. Esto se debe a que quiero evitar comprometer los tres compromisos de cambio local. Luego, me comprometo desde la rama maestra y rebaso todo.
Vale la pena ejecutar
git svn dcommit -n
primero para asegurarse de que está a punto de comprometer exactamente lo que pretende cometer. A diferencia de git, ¡reescribir el historial en svn es difícil!Siento que debe haber una mejor manera de fusionar el cambio en una rama temática mientras se omiten esos compromisos de cambio local que usar cherry-pick, por lo que si alguien tiene alguna idea, sería bienvenido.
fuente
Solución simple: eliminar la rama 'trabajo' después de fusionar
Respuesta corta: puede usar git como desee (consulte a continuación un flujo de trabajo simple), incluida la fusión. Solo asegúrese de seguir cada ' trabajo de fusión git ' con ' git branch -d work ' para eliminar la rama de trabajo temporal.
Explicación de fondo: El problema de combinación / dcommit es que siempre que 'git svn dcommit' una rama, el historial de fusión de esa rama se 'aplana': git se olvida de todas las operaciones de fusión que entraron en esta rama: solo se preserva el contenido del archivo, pero se pierde el hecho de que este contenido (parcialmente) proviene de otra rama específica. Ver: ¿Por qué git svn dcommit pierde el historial de confirmaciones de fusión para sucursales locales?
(Nota: no hay mucho que git-svn pueda hacer al respecto: svn simplemente no comprende las combinaciones de git mucho más potentes. Por lo tanto, dentro del repositorio de svn, esta información de combinación no se puede representar de ninguna manera).
Pero este es todo el problema. Si elimina la rama 'trabajo' después de que se haya fusionado con la 'rama maestra', entonces su repositorio git está 100% limpio y se ve exactamente como su repositorio svn.
Mi flujo de trabajo: Por supuesto, primero cloné el repositorio svn remoto en un repositorio git local (esto puede llevar algo de tiempo):
Todo el trabajo se realiza dentro del "directorio local". Cada vez que necesito obtener actualizaciones del servidor (como 'svn update'), hago:
Hago todo mi trabajo de desarrollo en una rama separada 'trabajo' que se crea así:
Por supuesto, puede crear tantas ramas para su trabajo como desee y fusionarlas y volver a crearlas 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:
El siguiente paso (git rebase -i) es opcional --- es solo limpiar el historial antes de archivarlo en svn: una vez que alcancé una piedra estable que quiero compartir con los demás, reescribo el historial de este 'trabajo' bifurca y limpia 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
y copie el hash sha-1 del último commit que esté activo en el repositorio svn (como lo indica un git-svn-id). Entonces llamo
Solo pegue 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 detalles. En resumen: este comando primero abre un editor que presenta sus confirmaciones ---- solo cambie 'elegir' a 'aplastar' para todas las confirmaciones que desea eliminar con las confirmaciones anteriores. Por supuesto, la primera línea debe permanecer como una "elección". De esta manera, puede condensar sus muchos pequeños compromisos en una o más unidades significativas. Guarde y salga del editor. Obtendrá otro editor que le pedirá que reescriba los mensajes de registro de confirmación.
En resumen: después de terminar el 'pirateo de códigos', masajeo mi rama 'trabajo' hasta que se vea cómo quiero presentarlo a los otros programadores (o cómo quiero ver el trabajo dentro de unas semanas cuando navego por el historial) .
Para enviar los cambios al repositorio svn, hago:
Ahora estamos de vuelta en la antigua rama 'maestra' 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 chocar con sus nuevos cambios de 'trabajo', debe resolverlos localmente antes de que pueda impulsar su nuevo trabajo (vea los detalles más abajo). Entonces, podemos empujar nuestros cambios a svn:
Nota 1: El comando 'git branch -d work' es bastante seguro: solo le permite eliminar ramas que ya no necesita (porque ya están fusionadas en su rama actual). Si ejecuta este comando por error antes de fusionar su trabajo con la rama 'maestra', recibirá un mensaje de error.
Nota 2: asegúrese de eliminar su rama con 'git branch -d work' entre la fusión y dcommit: si intenta eliminar la rama después de dcommit, recibirá un mensaje de error: cuando hace 'git svn dcommit', git olvida que su sucursal se ha fusionado con 'maestro'. Debe eliminarlo con 'git branch -D work' que no realiza la verificación de seguridad.
Ahora, inmediatamente creo una nueva rama 'de trabajo' para evitar piratear accidentalmente la rama 'maestra':
Integrando su 'trabajo' con cambios en svn: Esto es lo que hago cuando 'git svn rebase' revela que otros cambiaron el repositorio de svn mientras estaba trabajando en mi rama 'trabajo':
Existen soluciones más potentes: el flujo de trabajo presentado es simplista: utiliza los poderes de git solo dentro de cada ronda de 'actualizar / piratear / dcommitir', pero deja el historial del proyecto a largo plazo tan lineal como el repositorio svn. Esto está bien si solo desea comenzar a usar git merges en pequeños primeros pasos en un proyecto svn heredado.
Cuando se familiarice con git merging, siéntase libre de explorar otros flujos de trabajo: si sabe lo que está haciendo, puede mezclar git merges con svn merges (¿ Usando git-svn (o similar) solo para ayudar con svn merge? )
fuente
git merge --squash work
, ¿por qué no hacer esto? Puedo ver hacer commits de squash en la rama antes de fusionar si está creando más de una 'selección' (digamos que tiene 8 commits y está convirtiendo cada uno de 4 commits en 1, y fusionando 2 commits para masterizar). Además, cuando actualizo mi rama 'trabajo', lo hagorebase
, es más simple que crear otra rama para mi rama y hacer fusiones ...¡La respuesta de Greg Hewgill en la parte superior no es segura! Si aparecieron nuevas confirmaciones en el enlace troncal entre los dos "git svn rebase", la fusión no avanzará rápidamente.
Se puede garantizar mediante el uso de la bandera "--ff-only" para git-merge, pero generalmente no ejecuto "git svn rebase" en la rama, solo "git rebase master" (suponiendo que sea solo un local rama). Luego, se garantiza que un "git merge thebranch" será un avance rápido.
fuente
Una forma segura de fusionar ramas svn en git es usar git merge --squash. Esto creará una única confirmación y detendrá la adición de un mensaje.
Digamos que tiene un tema svn branch, llamado svn-branch.
en este punto, tiene todos los cambios de la rama svn aplastada en una confirmación esperando en el índice
fuente
Rebase la rama local de git en la rama maestra de git, luego dcommit y de esa manera parece que hiciste todos esos commits en secuencia para que la gente pueda verlo linealmente como están acostumbrados. Entonces, suponiendo que tenga una rama local llamada tema que podría hacer
que luego jugará sus commits sobre la rama maestra lista para que usted se comprometa
fuente