Enviar un repositorio Git existente a SVN
He estado haciendo todo mi trabajo en Git y enviándolo a GitHub. Estoy muy contento tanto con el software como con el sitio y no deseo cambiar mis prácticas de trabajo en este momento.
Mi asesor de doctorado pide a todos los estudiantes que mantengan su trabajo en un repositorio SVN alojado en la universidad. Encontré toneladas de documentación y tutoriales sobre cómo desplegar un repositorio SVN existente en Git, pero nada sobre cómo enviar un repositorio Git a un repositorio SVN nuevo. Supongo que debe haber alguna manera de hacer esto con una combinación de git-svn y una nueva rama y rebase y todos esos maravillosos términos, pero soy un novato en Git y no me siento seguro con ninguno de ellos.
Luego quiero ejecutar un par de comandos para enviar confirmaciones a ese repositorio SVN cuando lo desee. Deseo seguir usando Git y que el repositorio SVN refleje lo que hay en Git.
Seré la única persona que se comprometa con SVN, si esto hace alguna diferencia.
Yo también necesitaba esto, y con la ayuda de la respuesta de Bombe y un poco de manipulación, lo hice funcionar. Aquí está la receta:
Importar Git -> Subversión
1. cd /path/to/git/localrepo
2. svn mkdir --parents protocol:///path/to/repo/PROJECT/trunk -m "Importing git repo"
3. git svn init protocol:///path/to/repo/PROJECT -s
4. git svn fetch
5. git rebase origin/trunk
5.1. git status
5.2. git add (conflicted-files)
5.3. git rebase --continue
5.4. (repeat 5.1.)
6. git svn dcommit
Después del punto 3, recibirás un mensaje críptico como este:
Usando un nivel superior de URL:
protocol:///path/to/repo/PROJECT => protocol:///path/to/repo
Simplemente ignora eso.
Cuando ejecuta el n.° 5, es posible que obtenga conflictos. Resuélvalos agregando archivos con el estado "no fusionado" y reanudando la rebase. Con el tiempo, habrás terminado; luego sincronice nuevamente con el repositorio SVN, usando dcommit
. Eso es todo.
Mantener los repositorios sincronizados
Ahora puede sincronizar desde SVN a Git usando los siguientes comandos:
git svn fetch
git rebase trunk
Y para sincronizar de Git a SVN, use:
git svn dcommit
nota final
Es posible que desees probar esto en una copia local, antes de aplicarlo a un repositorio en vivo. Puedes hacer una copia de tu repositorio Git en un lugar temporal; simplemente use cp -r
, ya que todos los datos están en el repositorio mismo. Luego puede configurar un repositorio de pruebas basado en archivos, usando:
svnadmin create /home/name/tmp/test-repo
Y consulte una copia de trabajo, usando:
svn co file:///home/name/tmp/test-repo svn-working-copy
Eso te permitirá jugar con las cosas antes de realizar cambios duraderos.
Anexo: Si te equivocasgit svn init
Si ejecuta accidentalmente git svn init
con la URL incorrecta y no fue lo suficientemente inteligente como para realizar una copia de seguridad de su trabajo (no pregunte...), no puede simplemente volver a ejecutar el mismo comando. Sin embargo, puedes deshacer los cambios emitiendo:
rm -rf .git/svn
edit .git/config
Y elimine la [svn-remote "svn"]
sección de la sección.
Luego puedes ejecutar git svn init
de nuevo.
Así es como lo hicimos funcionar:
Clona tu repositorio Git en algún lugar de tu máquina.
Abra .git/config
y agregue lo siguiente (de Mantenimiento de un espejo SVN de solo lectura de un repositorio Git ):
[svn-remote "svn"]
url = https://your.svn.repo
fetch = :refs/remotes/git-svn
Ahora, desde una ventana de consola, escribe esto:
git svn fetch svn
git checkout -b svn git-svn
git merge master
Ahora, si se interrumpe aquí por cualquier motivo, escriba estas tres líneas:
git checkout --theirs .
git add .
git commit -m "some message"
Y finalmente, puedes comprometerte con SVN:
git svn dcommit
Nota: siempre elimino esa carpeta después.
El uso git rebase
directo perderá la primera confirmación. Git lo trata de manera diferente y no puede cambiar su base.
Existe un procedimiento que preservará el historial completo: http://kerneltrap.org/mailarchive/git/2008/10/26/3815034
Transcribiré la solución aquí, pero los créditos son para Björn.
Inicializa git-svn:
git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2
El --prefix le proporciona ramas de seguimiento remoto como "svn/trunk", lo cual es bueno porque no obtiene nombres ambiguos si llama a su sucursal local simplemente "trunk". Y -s
es un atajo para el diseño estándar de troncales/etiquetas/sucursales.
Obtenga el material inicial de SVN:
git svn fetch
Ahora busque el hash de su confirmación raíz (debería mostrar una única confirmación):
git rev-list --parents master | grep '^.\{40\}$'
Luego obtenga el hash de la confirmación del baúl vacío:
git rev-parse svn/trunk
Crea el injerto:
git replace --graft <root-commit-hash> <svn-trunk-commit-hash>
Ahora, "gitk" debería mostrarse svn/trunk
como la primera confirmación en la que se basa su rama maestra.
Haga que el injerto sea permanente:
git filter-branch -- ^svn/trunk --all
Soltar el injerto:
git replace -d <root-commit-hash>
gitk aún debería aparecer svn/trunk
en la ascendencia de master.
Linealiza tu historial en la parte superior del tronco:
git svn rebase
Y ahora "git svn dcommit -n" debería indicarle que se comprometerá con el troncal.
git svn dcommit
Cree un nuevo directorio en el repositorio de Subversion para su proyecto.
# svn mkdir --parents svn://ip/path/project/trunk
Cambie a su proyecto administrado por Git e inicialice git-svn.
# git svn init svn://ip/path/project -s
# git svn fetch
Esto creará una confirmación única porque el directorio de su proyecto SVN todavía está vacío. Ahora vuelva a basar todo en ese compromiso git svn dcommit
y debería haber terminado. Sin embargo, arruinará seriamente tus fechas de compromiso.
Git -> SVN con historial de confirmaciones completo
Tenía un proyecto Git y tuve que trasladarlo a SVN. Así es como lo hice, manteniendo todo el historial de confirmaciones. Lo único que se pierde es la hora de confirmación original, ya que libSVN establecerá la hora local cuando lo hagamos git svn dcommit
.
Cómo:
Tener un repositorio SVN donde queremos importar nuestro material y clonarlo con git-svn:
git svn clone https://path.to/svn/repository repo.git-svn`
Ve allí:
cd repo.git-svn
Agregue el control remoto del repositorio Git (en este ejemplo estoy usando C:/Projects/repo.git ). Quieres enviar a SVN y darle el nombre old-git:
git remote add old-git file:///C/Projects/repo.git/
Obtenga la información de la rama maestra del repositorio antiguo de git al repositorio actual:
git fetch old-git master
Extraiga la rama maestra del antiguo git remoto en una nueva rama llamada antigua en el repositorio actual:
git checkout -b old old-git/master`
Rebase para poner el HEAD encima de old-git/master. Esto mantendrá todas sus confirmaciones. Básicamente, lo que esto hace es tomar todo el trabajo realizado en Git y colocarlo encima del trabajo al que accede desde SVN.
git rebase master
Ahora regresa a tu rama maestra:
git checkout master
Y puede ver que tiene un historial de confirmaciones limpio. Esto es lo que desea enviar a SVN.
Envía tu trabajo a SVN:
git svn dcommit
Eso es todo. Es muy limpio, sin piratería y todo funciona perfectamente desde el primer momento. Disfrutar.