2009-07-23 5 views
13

J'ai les télécommandes Foo et Bar. Foo est une application web qui a beaucoup de répertoires, parmi lesquels /public qui contient des fichiers assortis et d'autres répertoires.git: est-ce que je peux fusionner un sous-chemin d'un dépôt?

Bar est un ensemble de bibliothèques et ce qui n'est pas utilisé sur le front-end, en tant que tel, il devrait aller dans /public/bar dans Foo. Foo n'a pas de fichiers là-bas.

Tout cela serait un jeu d'enfant avec des sous-modules ou une fusion de sous-arbres. Cependant ...

L'arbre de Bar est désordonné, il a toutes sortes de fichiers de pré-production comme les PSD et les FLA, et la seule partie vraiment utile est ce qui est à l'intérieur de son /www/tools. Donc, ce que je veux faire est de fusionner /www/tools de Bar dans /public/bar de Foo, et prétendre que le reste de l'arbre de Bar n'existe même pas.

Peut faire?

(je suppose que cela est très similaire à la façon dont la fusion d'un projet qui à l'origine comme la vôtre a fusionné sous-arbre. Ce que je ne sais pas comment faire, que ce soit.)

Répondre

0

Je ne pense pas que cela peut être fait en utilisant une fusion, en soi, mais ces étapes pourraient faire l'affaire, au moins en ce qui concerne le produit final. Tout d'abord:

% git fetch Bar 

Ce dernier récupère les commettras (s) à partir du référentiel Bar, mais ne pas essayer de les fusionner. Il enregistre le CSA pour la validation dans .git/FETCH_HEAD

% cat .git/FETCH_HEAD 
b91040363160aab4b5dd46e61e42092db74b65b7    branch 'Bar' of ssh://blah... 

Cela montre ce que l'identifiant SHA pour la dernière commit de la branche à distance est.

% git checkout b91040363160aab4b5dd46e61e42092db74b65b7 www/tools 

Cela prend la copie des fichiers www/outils pour l'engager et tiré par les cheveux ce qui est dans écrase l'arbre de travail. Vous pouvez ensuite valider ces modifications dans votre référentiel local comme d'habitude. Le commit résultant n'aura aucune référence à l'endroit d'où il provient, mais il devrait au moins obtenir votre référentiel avec les versions des fichiers que vous voulez.

+0

Oui, je serais heureux de garder l'histoire. Peut-être que quelque chose pourrait être fait avec filter-branch. – kch

+1

1.) vous pouvez utiliser "git checkout FETCH_HEAD www/tools" 2.) probablement vous pouvez utiliser "git checkout --merge FETCH_HEAD www/tools" 3.) après l'enregistrement de l'état requis dans le répertoire de travail, vous pouvez créer une fusion à la main en écrivant FETCH_HEAD à .git/MERGE_HEAD avant git-commit –

+0

Ah, je savais qu'il devait y avoir une meilleure façon de faire la partie FETCH_HEAD –

2

Edit: Il me semble que vous pourriez le faire avec git merge --no-commit. Cela va tenter la fusion, et même si elle n'est pas en conflit, elle s'arrêtera juste avant de commettre. À ce stade, vous pouvez supprimer tout le courrier indésirable dont vous n'avez pas besoin (y compris la restauration des fichiers en conflit si nécessaire) et créer un commit de fusion contenant uniquement le sous-arbre souhaité.

réponse originale:

Vous pouvez en effet utiliser pour cette branche de filtre. Un aperçu:

Clone votre repo source:

git clone --bare /path/to/bar /path/to/bar_clone 

L'utilisation d'un clone nu vous permettra d'économiser le temps et l'espace de la création d'un répertoire de travail.

Ensuite, utilisez le filtre-branche sur le clone: ​​

git filter-branch --index-filter 'git rm -rf <unwanted files/directories>' -- --all 

Le --all le laisse savoir que vous voulez utiliser tous les refs, pas seulement la tête en cours.Vous allez maintenant avoir un référentiel contenant uniquement le sous-répertoire souhaité et tout l'historique associé à celui-ci.

Note: Désolé, je ne connais pas un moyen très simple de supprimer tout sauf ce que vous voulez. Vous devez être prudent avec les caractères génériques car vous ne voulez pas écraser les répertoires git. Voici quelque chose qui va travailler, mais il est plus lent, surtout si vous avez beaucoup de fichiers:

git filter-branch --index-filter 'git rm -f `git ls-files | grep -v ^www/tools`' -- --all 

Quoi qu'il en soit, mais vous gérer la liste des fichiers à supprimer, vous pouvez aller de l'avant avec l'opération de fusion sous-arbre, tirant de bar_clone en foo.

3

Essayez d'utiliser git subtree pour cela. Il vous permet d'extraire un sous-arbre d'un projet dans un autre projet, que vous pouvez ensuite fusionner dans le vôtre.

+0

Pouvez-vous spécifier comment faire cela? J'essaie de résoudre ce problème ici: http://stackoverflow.com/questions/30704352/sub-directory-into-independent-repository-and-later-merge-back-into-main-reposit –

10

Je l'ai fait avec succès en utilisant les commandes suivantes (réécrites pour votre scénario).

$ git remote add Bar /path/to/bar 
$ git merge -s ours --no-commit Bar/master 
$ git read-tree --prefix=public/bar -u Bar/master:www/tools/ 

ÉNORME AVERTISSEMENT! Je suis encore en train de trouver comment faire une extraction/fusion de Bar. Cela apportera tout juste une fois.

Ma façon actuelle de la fusion des changements est comme ceci:

$ get fetch Bar 
$ git pull -X subtree=public/bar Bar master 

Cela vous laissera des conflits en disant qu'une tonne de fichiers ont été supprimés, il vous suffit git rm puis les git commit.

Je suis certainement ouvert aux suggestions sur une meilleure façon d'apporter des modifications.

Puisqu'il s'agit d'un ancien thread, je devrais ajouter que je cours Git 1.7.9.

+0

Un problème avec ce est qu'il apporte dans tous les commits de la branche, non seulement ceux qui affectent le sous-répertoire. Y a-t-il un moyen de contourner cela? – pmr

+0

Si vous fusionnez plusieurs référentiels, vous pouvez passer '--allow-unrelated-histories' pour fusionner. –

0

Je suggère d'utiliser deux fois subtree - une fois pour extraire tous les/www/tools et une fois pour extraire/public - il semble que/public devrait être dans son propre repo, donc je vous suggère de pousser/public à un nouveau repo - avec tout son historique de sous-arbre, puis fusionnez l'historique de sous-arbre de/www/tools dans le nouveau repo public et ajoutez-le en tant que sous-arbre de Foo.

cd foo 
git subtree split --prefix=public --branch=new-shared-public --annotate='(split) ' 
cd../bar 
git subtree split --prefix=www/tools --rejoin --branch=new-shared-www-tools --annotate='(split) ' 

Vous avez maintenant deux nouvelles branches sur vos dépôts. Un avec l'histoire de commit du public et l'autre avec www/tools. Je vais omettre cd à partir d'ici.

Créer votre nouveau repo public (je suppose github ici, mais sonne comme vous pouvez le faire localement) et pousser votre sous-arbre là-bas: git checkout nouveau partage public git pousser [email protected]: mon_id/nouvelle-partagée-repo.git TÊTE: maître

ensuite fusionner votre autre branche dans ce:

git checkout new-shared-www-tools 
git remote add Foo [email protected]:my_id/new-shared-repo.git 
git merge -s ours --no-commit Bar/master 

Bien que j'ai spécifié ours que la politique de commettre, il a probablement (probablement) doesn Peu importe.

Enfin, après avoir effectué la fusion et l'avoir envoyée au nouveau dépôt, retournez au dépôt Foo.Git rm l'histoire publique à partir de là et ajouter le nouveau repo public comme un sous-arbre:

git subtree add --squash --prefix shared [email protected]:my_id/new-shared-repo.git master 
git subtree pull --squash --prefix shared [email protected]:my_id/new-shared-repo.git master 
git push 
Questions connexes