2011-07-09 2 views
8

J'ai un référentiel et je voudrais détacher un de ses répertoires dans un nouveau repo. This est un endroit parfait pour commencer, il y a une mise en garde, cependant: le répertoire que je veux détacher a été renommé à un moment donné. Et si je suis la solution de ce poste avec le nouveau nom du répertoire, il semble que je perds l'historique avant le nouveau nom. Des idées d'un tweak pour le faire fonctionner dans cette situation?Détacher le sous-répertoire (qui a été renommé!) Dans un nouveau dépôt

Répondre

9

git filter-branch peut fonctionner sur des plages de commits; donc ce que nous pouvons faire est de filtrer le « avant » et « après » séparément, et l'utilisation de greffons pour les virer de bord ainsi:

git branch rename $COMMIT_ID_OF_RENAME 
git branch pre-rename rename~ 
## First filter all commits up to rename, but not rename itself 
git filter-branch --subdirectory-filter $OLDNAME pre-rename 
## Add a graft, so our rename rev comes after the processed pre-rename revs 
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts 
## The first filter-branch left a refs backup directory. Move it away so the 
## next filter-branch doesn't complain 
mv .git/refs/original .git/refs/original0 
## Now filter the rest 
git filter-branch --subdirectory-filter $NEWNAME master ^pre-rename 
## The graft is now baked into the branch, so we don't need it anymore 
rm .git/info/grafts 

Ceci est légèrement plus complexe si vous avez besoin de filtrer plusieurs branches ou étiquettes; Les branches avant le renommage peuvent être incluses dans la première branche de filtre, tandis que les suivantes doivent être incluses avant la ^rename dans la seconde branche de filtre.

Une autre option serait d'ajouter un filtre d'index (ou un filtre d'arborescence) à la place qui vérifie les deux répertoires, anciens et nouveaux, et garde celui qui est présent.

Puisque vous n'avez pas fourni un référentiel de test, voici un script bon sens vérification rapide pour ce scénario:

#!/bin/bash 

set -u 
set -e 
set -x 

rm -rf .git x y foo 

git init 
mkdir x 
echo initial > x/foo 
git add x/foo 
git commit -m 'test commit 1' 

echo tc2 >> x/foo 
git commit -a -m 'test commit 2' 

mv x y 
git rm x/foo 
git add y/foo 
git commit -a -m 'test rename' 

git branch rename HEAD 

echo post rename >> y/foo 
git commit -a -m 'test post rename' 

git branch pre-rename rename~ 

git filter-branch --subdirectory-filter x pre-rename 
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts 

mv .git/refs/original .git/refs/original0 

git filter-branch --subdirectory-filter y master ^pre-rename 

rm .git/info/grafts 

git log -u 

Si cette procédure ne fonctionne pas pour vous, alors il est susceptible d'être autre chose étrange à propos de l'historique de votre référentiel que vous n'avez pas décrit, comme un autre changement de nom qui se cache dans l'historique.

+0

Hmm, j'ai essayé votre méthode avec des greffes (dont je ne sais rien) et il ne fonctionne pas pour moi. Après le traitement de l'un des commits "avant" est vide, les fichiers d'un autre ont été déplacés dans la racine du repo; Je ne peux pas le comprendre. Je pensais avant d'utiliser un filtre à arbre mais je n'ai aucune expérience avec ça; auriez-vous intérêt à élaborer me montrer quelques indications? – akoprowski

+0

Etes-vous sûr que le commit précédent utilisait le sous-répertoire correct? Pouvez-vous poster votre repo git quelque part? – bdonlan

+0

Yup, renommer était sur le commit qui a fait le renommage et le pré-renommer juste avant. Le repo est énorme et en partie privé, donc je ne peux pas vraiment le publier n'importe où: | – akoprowski

Questions connexes