git-svn: qual é o equivalente a `svn switch --relocate`?


87

Um repositório svn que estou espelhando por meio de git-svn mudou de URL.

Em vanilla svn, você apenas faria svn switch --relocate old_url_base new_url_base.

Como posso fazer isso usando git-svn?

Simplesmente alterar o url svn no arquivo de configuração falha.


Você deve tentar e possivelmente aceitar esta resposta: stackoverflow.com/a/4061493/1221661
Fritz

Resposta mais atualizada: stackoverflow.com/a/40523789/537554 . Mesma pergunta, mas feita da perspectiva de um usuário Git.
ryenus,

Respostas:


61

Isso lida muito bem com minha situação:

https://git.wiki.kernel.org/index.php/GitSvnSwitch

Eu clonei usando o file://protocolo e queria mudar para o http://protocolo.

É tentador editar a urlconfiguração na [svn-remote "svn"]seção de .git/config, mas por si só isso não funciona. Em geral, você precisa seguir o seguinte procedimento:

  1. Mude a urlconfiguração svn-remote para o novo nome.
  2. Corra git svn fetch. Isso precisa buscar pelo menos uma nova revisão do svn!
  3. Altere a urlconfiguração svn-remote de volta para a URL original.
  4. Execute git svn rebase -lpara fazer um rebase local (com as mudanças que vieram com a última operação de busca).
  5. Mude a urlconfiguração svn-remote de volta para a nova URL.
  6. Agora, git svn rebasedeve funcionar novamente.

Almas aventureiras podem querer tentar --rewrite-root.


2
para ser justo, isso realmente falhou para mim, e acabei clonando novamente o repo. É difícil fazer o git lidar com isso quando o diretório svn é renomeado.
Gregg Lind

Eu preferiria aceitar um texto mais detalhado, mas justo, aceitarei até que apareça uma nova resposta.
kch

2
Aqui está outra descrição desse procedimento: theadmin.org/articles/git-svn-switch-to-a-different-a-svn-url
n8gray

o link fornecido na resposta aceita está desatualizado e o novo a partir de agora é: git.wiki.kernel.org/articles/g/i/t/GitSvnSwitch_8828.html Segui o "Caso Geral" e era simples e realmente funcionou bem.
TcMaster de

2
@TcMaster: funcionou para mim também ... mas é por isso que as respostas não devem conter apenas links, elas ficam desatualizadas e se tornam inúteis ... Vou adicionar uma resposta do wiki da comunidade.
UncleZeiv

36

Você pode ver se o seguinte funciona bem:

  1. Se svn-remote.svn.rewriteRootnão existir no arquivo de configuração ( .git/config):

    git config svn-remote.svn.rewriteRoot <currentRepositoryURL>
    
  2. Se svn-remote.svn.rewriteUUIDnão existir no arquivo de configuração:

    git config svn-remote.svn.rewriteUUID <currentRepositoryUUID>
    

    O currentRepositoryUUIDpode ser obtido em .git/svn/.metadata.

  3. git config svn-remote.svn.url <newRepositoryURL>


Fantástico - obrigado, funcionou muito bem para mim (clonado via file://, alternar para svn+ssh); apenas observando que: este procedimento não precisa "buscar pelo menos uma nova revisão do svn"; também ./.git/svn/.metadataapós primeiro svn rebasecontém o <newRepository>as reposRoot- mas isso não é suficiente para remover as rewrite*chaves .git/config; portanto, essas chaves devem ser mantidas permanentemente lá, tanto quanto eu entendo.
sdaau

1
Funcionou para mim também, como um encanto. O OP deve tentar este e obtê-lo como a resposta correta.
Rafareino

Perfeito. Eu tinha um grande projeto com milhares de commits no histórico, então um novo clone teria destruído o histórico (ou demoraria muito para fazer o checkout). Estou usando svn+ssh://e nosso svn-server acabou de mudar o domínio de .separa .compara limpar nossa nomenclatura interna.
UlfR 01 de

Funcionou muito bem para mim. Tinha um repo de 2 anos com 1.000s de commits, o repo foi movido para um novo host, então isso evitou um (temido) clone svn completo.
David Victor

21

Infelizmente, a maioria dos links nessas respostas não está funcionando, então vou duplicar um pouco de informação do wiki git para referência futura.

Esta solução funcionou para mim:

  • Edite o svn-remote url(ou fetchcaminho) .git/configpara apontar para o novo domínio / url / caminho

  • Execute git git svn fetch. Isso precisa buscar pelo menos uma nova revisão do svn!

  • Se você tentar git svn rebaseagora, receberá uma mensagem de erro como esta:

    Unable to determine upstream SVN information from working tree history
    

    Acho que isso ocorre porque git svnestá confuso pelo fato de que seu último commit anterior à busca terá um git-svn-idapontando para o caminho antigo, que não corresponde ao encontrado em .git/config.

  • Como solução alternativa, altere svn-remote url(ou fetchcaminho) de volta para o domínio / url / caminho original

  • Agora execute git svn rebase -lnovamente para fazer um rebase local com as mudanças que vieram com a última operação de busca. Desta vez ele vai trabalhar, aparentemente porque git svnnão será confundido pelo fato de que o git-svn-iddo novo chefe não coincide com o encontrado em .git/config.

  • Finalmente, mude svn-remote url(ou fetchcaminho) de volta para o novo domínio / url / caminho

  • Neste ponto, git svn rebasedeve funcionar novamente!

A informação original foi encontrada aqui .



2

git filter-branch

Este script , retirado de uma entrada de blog , funcionou para mim. Forneça o URL do repo antigo e o novo como parâmetro, assim como para svn switch --relocate.

O script chama git filter-branchpara substituir URLs do Subversion nas git-svn-idmensagens de commit, atualizações .git/confige também atualiza git-svnmetadados recriando-os usando git svn rebase. Embora git svn clonepossa ser a solução mais robusta, a filter-branchabordagem funciona muito mais rápido para repositórios enormes (horas x dias).

#!/bin/sh

# Must be called with two command-line args.
# Example: git-svn-relocate.sh http://old.server https://new.server
if [ $# -ne 2 ]
then
  echo "Please invoke this script with two command-line arguments (old and new SVN URLs)."
  exit $E_NO_ARGS
fi

# Prepare URLs for regex search and replace.
oldUrl=`echo $1 | awk '{gsub("[\\\.]", "\\\\\\\&");print}'`
newUrl=`echo $2 | awk '{gsub("[\\\&]", "\\\\\\\&");print}'`

filter="sed \"s|^git-svn-id: $oldUrl|git-svn-id: $newUrl|g\""
git filter-branch --msg-filter "$filter" -- --all

sed -i.backup -e "s|$oldUrl|$newUrl|g" .git/config

rm -rf .git/svn
git svn rebase

1

git_fast_filter

Ainda mais rápido do que git-filter-branch(ou seja, minutos em vez de horas), mas semelhante em espírito, é usar git_fast_filter. No entanto, isso requer um pouco mais de codificação e não existe uma solução pronta para uso. Em contraste com git-filter-branch, isso criará um novo repo a partir de um antigo . Presume-se que masteraponta para o último commit do SVN.

  1. Clone git_fast_filterdo repositório Gitorious.
  2. Crie um script Python no mesmo diretório onde você clonou com git_fast_filterbase neste Gist , defina o bit executável usando chmod +x. Adapte caminhos de repositório novos e antigos. (O conteúdo do script também é colado abaixo.)
  3. Inicialize um novo repositório de destino usando git init, altere o diretório de trabalho para este novo repo.
  4. Execute o seguinte tubo:

    (cd path/to/old/repo && git-fast-export --branches --tags --progress=100) | \
        path/to/git_fast_filter/commit_filter.py | git-fast-import
    
  5. Copie .git/confige talvez outros arquivos relevantes .git/infodo repositório antigo para o novo.

  6. Remova .git/svn.
  7. Esteja git-svnciente do novo mapeamento de número de revisão

    1. Executar git branch refs/remotes/git-svn master

      • Seus remotes git-svn podem ter nomes diferentes de refs/remotes/git-svn, consultar .git/config, svn-remoteseções
    2. Execute git svn info. Se este comando congelar, algo está errado. Ele deve reconstruir o mapeamento do número de revisão.

    3. Remova o galho falso refs/remotes/git-svn, ele será recriado porgit-svn

  8. Sincronize ligando git svn rebase.

Abaixo está o conteúdo de commit_filter.py, substitua os valores de IN_REPOe OUT_REPOconforme apropriado:

#!/usr/bin/python

from git_fast_filter import Commit, FastExportFilter
import re
import sys

IN_REPO = "https://svn.code.sf.net/p/matsim/code"
OUT_REPO = "https://svn.code.sf.net/p/matsim/source"

IN_REPO_RE = re.compile("^git-svn-id: %s" % re.escape(IN_REPO), re.M)
OUT_REPO_RE = "git-svn-id: %s" % OUT_REPO

def my_commit_callback(commit):
  commit.message = IN_REPO_RE.sub(OUT_REPO_RE, commit.message)
  sys.stderr.write(".")

filter = FastExportFilter(commit_callback = my_commit_callback)
filter.run()

0

A git svn rebase -lsolução acima não funcionou para mim. Decidi fazer isso de uma maneira diferente:

  1. Clone o antigo SVN repo no git repo olde o novo SVN no git reponew
  2. Buscar oldemnew
    • cd new
    • git fetch ../old
    • git tag old FETCH_HEAD
  3. Rebase newno topo old(deve funcionar porque as árvores na raiz newe na ponta de oldsão idênticas)
    • git checkout master(Presume que o masterbranch está apontando para o cabeçalho SVN. Esse será o caso com um clone limpo; caso contrário, dcommit antes de começar.)
    • git rebase --root --onto old
  4. Reconstrua os metadados git-svn de newpara contabilizar o rebase
    • git update-ref --no-deref refs/remotes/git-svn master(ajuste a referência remota dependendo de como você clonou, por exemplo, pode ser refs/remotes/svn/trunk)
    • rm -r .git/svn
    • git svn info

1. Você começa com um novo clone do novo local para um novo? Se sim, por que você ainda não terminou? 2. Se você realocar o novo no antigo, todos os seus commits antigos mencionam a URL antiga em sua entrada de registro de commits svn-id? 3. Existe alguma documentação que é salva para remover .git / svn? (3b: qual comando está reconstruindo os metadados git-svn, git svn info?)
Micha Wiedenmann

0

Com base em algumas das outras respostas a esta pergunta, eu vim com um script Ruby que lida com a realocação de git-svn. Você pode encontrá-lo em https://gist.github.com/henderea/6e779b66be3580c9a584 .

Ele lida com a realocação sem fazer check-out de outra cópia, e ainda lida com o caso em que há alterações não enviadas em um ou mais branches (já que isso quebra a lógica regular). Ele usa coisas da resposta do git filter-branch (para a lógica principal) e a resposta sobre a cópia de branches de uma instância do repo para outra (para copiar branches com alterações não enviadas).

Tenho usado isso para realocar um monte de repositórios git-svn que tenho para trabalhar, e esta versão do script (já passei por inúmeras iterações) parece funcionar para mim. Não é muito rápido, mas parece lidar com todos os casos que encontrei e resultar em um repositório totalmente realocado.

O script oferece a opção de criar uma cópia do repo antes de fazer qualquer alteração, portanto, você pode usar essa opção para criar um backup. A criação de uma cópia é necessária se você tiver alterações não enviadas em qualquer branch.

O script não usa gemas ou outras bibliotecas não incluídas na instalação normal do MRI Ruby. Ele usa as bibliotecas readline e fileutils incluídas no MRI.

Espero que meu script seja útil para outra pessoa. Sinta-se à vontade para fazer alterações no script.

NOTA: Eu apenas testei este script com git 2.3.0 / 2.3.1 e Ruby 2.2.0 no OS X 10.10 Yosemite (já que é o ambiente que uso), mas espero que funcione em outros ambientes também. Não há garantias sobre o Windows, no entanto.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.