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.

kch
fonte
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.

kch
fonte
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>

H Krishnan
fonte
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 .

UncleZeiv
fonte
3

Git svn depende muito da URL svn. Todo commit importado de svn possui um git-svn-idque inclui a URL svn.

Uma estratégia de realocações válida é chamar git-svn cloneo novo repositório e mesclar as mudanças naquele novo fechamento. Para um procedimento mais detalhado, consulte este artigo:

http://www.sanityinc.com/articles/relocating-git-svn-repositories

Adam Alexander
fonte
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
krlmlr
fonte
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()
krlmlr
fonte
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
Ben Challenor
fonte
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.

Eric Henderson
fonte