git-svn: quel est l'équivalent de `svn switch --relocate`?

87

Un dépôt svn que je mets en miroir via git-svn a changé d'URL.

Dans svn vanille, vous feriez juste svn switch --relocate old_url_base new_url_base.

Comment puis-je faire cela en utilisant git-svn?

La simple modification de l'url svn dans le fichier de configuration échoue.

kch
la source
Vous devriez essayer et éventuellement accepter cette réponse: stackoverflow.com/a/4061493/1221661
Fritz
Réponse la plus récente: stackoverflow.com/a/40523789/537554 . Même question, mais posée du point de vue d'un utilisateur Git.
ryenus

Réponses:

61

Cela gère assez bien ma situation:

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

J'ai cloné en utilisant le file://protocole et je voulais passer au http://protocole.

Il est tentant de modifier le urlparamètre dans la [svn-remote "svn"]section de .git/config, mais cela ne fonctionne pas en soi. En général, vous devez suivre la procédure suivante:

  1. Basculez le urlparamètre svn-remote sur le nouveau nom.
  2. Courez git svn fetch. Cela doit récupérer au moins une nouvelle révision de svn!
  3. Remplacez le urlparamètre svn-remote par l'URL d'origine.
  4. Exécutez git svn rebase -lpour effectuer un rebase local (avec les modifications apportées lors de la dernière opération d'extraction).
  5. Remplacez le urlparamètre svn-remote par la nouvelle URL.
  6. Maintenant, git svn rebasedevrait fonctionner à nouveau.

Les âmes aventureuses voudront peut-être essayer --rewrite-root.

kch
la source
2
pour être honnête, cela a échoué pour moi et j'ai fini par recloner le repo. Il est difficile de faire en sorte que git le gère lorsque le répertoire svn est renommé.
Gregg Lind
Je préférerais accepter une rédaction plus détaillée, mais assez juste, je l'accepterai jusqu'à ce qu'une nouvelle réponse arrive.
kch
2
Voici une autre description de cette procédure: theadmin.org/articles/git-svn-switch-to-a-different-a-svn-url
n8gray
le lien fourni dans la réponse acceptée est obsolète et le nouveau à partir de maintenant est: git.wiki.kernel.org/articles/g/i/t/GitSvnSwitch_8828.html J'ai suivi le «cas général» et c'était simple et vraiment a bien fonctionné.
TcMaster
2
@TcMaster: a fonctionné pour moi aussi ... mais c'est pourquoi les réponses ne doivent pas contenir que des liens, elles deviennent obsolètes et deviennent inutiles ... Je vais ajouter une réponse wiki de la communauté.
UncleZeiv
36

Vous pouvez voir si ce qui suit fonctionne bien:

  1. Si svn-remote.svn.rewriteRootn'existe pas dans le fichier de configuration ( .git/config):

    git config svn-remote.svn.rewriteRoot <currentRepositoryURL>
    
  2. Si svn-remote.svn.rewriteUUIDn'existe pas dans le fichier de configuration:

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

    Le currentRepositoryUUIDpeut être obtenu à partir de .git/svn/.metadata.

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

H Krishnan
la source
Fantastique - merci, cela a très bien fonctionné pour moi (cloné via file://, basculer vers svn+ssh); en notant simplement que: cette procédure n'a pas besoin de "récupérer au moins une nouvelle révision de svn"; aussi ./.git/svn/.metadataafter first svn rebasecontient le <newRepository>as reposRoot- mais cela ne suffit pas pour supprimer les rewrite*clés de .git/config; donc ces clés devraient y être conservées en permanence, pour autant que je sache.
sdaau
1
Cela a fonctionné pour moi aussi, comme un charme. L'OP devrait essayer celui-ci et l'obtenir comme la bonne réponse.
Rafareino
Parfait. J'avais un gros projet avec des milliers de commits dans l'histoire, donc un nouveau clone aurait détruit l'historique (ou prendrait beaucoup de temps à vérifier). J'utilise svn+ssh://et notre serveur svn vient de changer de domaine de .seà .compour nettoyer notre dénomination interne.
UlfR
A travaillé un régal pour moi. Avait un repo de 2 ans avec des milliers de commits, le repo a été déplacé vers un nouvel hôte, ce qui a évité un clone svn complet (redouté).
David Victor
21

Malheureusement, la plupart des liens dans ces réponses ne fonctionnent pas, donc je vais dupliquer un peu d'informations du wiki git pour référence future.

Cette solution a fonctionné pour moi:

  • Modifiez le svn-remote url(ou le fetchchemin) .git/configpour pointer vers le nouveau domaine / url / chemin

  • Exécutez git git svn fetch. Cela doit récupérer au moins une nouvelle révision de svn!

  • Si vous essayez git svn rebasemaintenant, vous obtiendrez un message d'erreur comme celui-ci:

    Unable to determine upstream SVN information from working tree history
    

    Je pense que c'est parce que git svnc'est confus par le fait que votre dernier commit avant la récupération aura un git-svn-idpointant vers l'ancien chemin, qui ne correspond pas à celui trouvé dans .git/config.

  • Pour contourner le problème, modifiez svn-remote url(ou le fetchchemin) vers le domaine / l'url / le chemin d'origine

  • Maintenant, exécutez à git svn rebase -lnouveau pour effectuer un rebase local avec les modifications apportées lors de la dernière opération d'extraction. Cette fois , il va travailler, apparemment parce que git svnne sera pas confondu par le fait que le git-svn-idde la nouvelle tête ne correspond pas à celle trouvée dans .git/config.

  • Enfin, changez svn-remote url(ou fetchchemin) vers le nouveau domaine / url / chemin

  • À ce stade, git svn rebasedevrait fonctionner à nouveau!

Les informations originales ont été trouvées ici .

OncleZeiv
la source
3

Git svn s'appuie fortement sur l'URL svn. Chaque commit importé de svn a un git-svn-idqui inclut l'URL svn.

Une stratégie de relocalisation valide consiste à appeler git-svn clonele nouveau référentiel et à fusionner les modifications sur cette nouvelle clôture. Pour une procédure plus détaillée, consultez cet article:

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

Adam Alexander
la source
2

git filter-branch

Ce script , tiré d' une entrée de blog , a fonctionné pour moi. Fournissez l'ancienne et la nouvelle URL du dépôt en tant que paramètre, comme pour svn switch --relocate.

Le script appelle git filter-branchà remplacer les URL Subversion dans les git-svn-idmessages de validation, les mises à jour .git/configet met également à jour les git-svnmétadonnées en les recréant à l'aide de git svn rebase. Bien que cela git svn clonepuisse être la solution la plus robuste, l' filter-branchapproche fonctionne beaucoup plus rapidement pour d'énormes référentiels (heures par rapport aux jours).

#!/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
la source
1

git_fast_filter

Pourtant, plus rapide que git-filter-branch(c'est-à-dire des minutes au lieu d'heures), mais similaire dans l'esprit, est à utiliser git_fast_filter. Cependant, cela nécessite un peu plus de codage, et aucune solution prête à l'emploi n'existe. Contrairement à git-filter-branch, cela créera un nouveau repo à partir d'un ancien . On suppose que masterpointe vers le dernier commit SVN.

  1. Clone git_fast_filterdu repo Gitorious.
  2. Créez un script Python dans le même répertoire où vous avez cloné en git_fast_filterfonction de ce Gist , définissez le bit exécutable à l'aide de chmod +x. Adaptez les anciens et les nouveaux chemins de référentiel. (Le contenu du script est également collé ci-dessous.)
  3. Initialisez un nouveau référentiel cible à l'aide de git init, remplacez le répertoire de travail par ce nouveau référentiel .
  4. Exécutez le tube suivant:

    (cd path/to/old/repo && git-fast-export --branches --tags --progress=100) | \
        path/to/git_fast_filter/commit_filter.py | git-fast-import
    
  5. Copiez .git/config, et peut-être d'autres fichiers pertinents .git/infode l'ancien référentiel vers le nouveau référentiel.

  6. Supprimer .git/svn.
  7. Prenez git-svnconnaissance du nouveau mappage des numéros de révision

    1. Exécuter git branch refs/remotes/git-svn master

      • Vos télécommandes git-svn peuvent être appelées différemment de refs/remotes/git-svn, consultez .git/config, svn-remotesections
    2. Exécutez git svn info. Si cette commande se bloque, quelque chose ne va pas. Il devrait reconstruire le mappage des numéros de révision.

    3. Retirez la fausse branche refs/remotes/git-svn, elle sera recréée pargit-svn

  8. Synchronisez en appelant git svn rebase.

Vous trouverez ci-dessous le contenu de commit_filter.py, remplacez les valeurs de IN_REPOet, OUT_REPOle cas échéant:

#!/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
la source
0

La git svn rebase -lsolution ci-dessus n'a pas fonctionné pour moi. J'ai décidé de procéder différemment:

  1. Cloner l'ancien repo SVN dans le repo git oldet le nouveau SVN dans le repo gitnew
  2. Récupérer olddansnew
    • cd new
    • git fetch ../old
    • git tag old FETCH_HEAD
  3. Rebase newau sommet de old(devrait réussir car les arbres à la racine newet à la pointe de oldsont identiques)
    • git checkout master(Suppose que la masterbranche pointe vers la tête SVN. Ce sera le cas avec un clone propre; sinon, dcommit avant de commencer.)
    • git rebase --root --onto old
  4. Reconstruisez les métadonnées git-svn de newpour tenir compte du rebase
    • git update-ref --no-deref refs/remotes/git-svn master(ajustez la référence de la télécommande en fonction de la façon dont vous avez cloné, par exemple, cela pourrait être refs/remotes/svn/trunk)
    • rm -r .git/svn
    • git svn info
Ben Challenor
la source
1. Commencez-vous par un nouveau clone du nouvel emplacement vers un nouveau? Si oui, pourquoi n'avez-vous pas terminé à ce stade? 2. Si vous rebasez le nouveau sur l'ancien, vos anciens commits mentionnent-ils tous l'ancienne URL dans leur entrée de journal de validation svn-id? 3. Existe-t-il une documentation sauvegardée pour supprimer .git / svn? (3b: quelle commande reconstruit les métadonnées git-svn, git svn info?)
Micha Wiedenmann
0

Sur la base de certaines des autres réponses à cette question, j'ai mis au point un script Ruby qui gère le déplacement de git-svn. Vous pouvez le trouver sur https://gist.github.com/henderea/6e779b66be3580c9a584 .

Il gère le déplacement sans extraire une autre copie, et il gère même le cas où il y a des modifications non poussées dans une ou plusieurs branches (car cela rompt la logique régulière). Il utilise des éléments de la réponse git filter-branch (pour la logique principale) et la réponse sur la copie de branches d'une instance du dépôt vers une autre (pour copier des branches avec des modifications non poussées).

Je l'ai utilisé pour déplacer un tas de dépôts git-svn que j'ai pour le travail, et cette version du script (j'ai traversé d'innombrables itérations) semble fonctionner pour moi. Ce n'est pas très rapide, mais il semble gérer tous les cas que j'ai rencontrés et aboutir à un dépôt entièrement relocalisé.

Le script vous donne la possibilité de créer une copie du dépôt avant d'apporter des modifications, vous pouvez donc utiliser cette option pour créer une sauvegarde. La création d'une copie est requise si vous avez des modifications non poussées dans des branches.

Le script n'utilise pas de gemmes ou d'autres bibliothèques non incluses dans l'installation normale de MRI Ruby. Il utilise les bibliothèques readline et fileutils incluses dans l'IRM.

J'espère que mon script sera utile à quelqu'un d'autre. N'hésitez pas à apporter des modifications au script.

REMARQUE: je n'ai testé ce script qu'avec git 2.3.0 / 2.3.1 et Ruby 2.2.0 sur OS X 10.10 Yosemite (puisque c'est l'environnement que j'utilise), mais je m'attendrais à ce qu'il fonctionne également sur d'autres environnements. Aucune garantie sur Windows, cependant.

Eric Henderson
la source