2012-01-03 3 views
4

J'ai un dépôt dans un sous-répertoire, et maintenant je voudrais aussi avoir les répertoires parents sous le contrôle de version, mais conserver l'historique actuel du référentiel.Comment développer un dépôt git?

Donc, avec l'arbre suivant:

c tient actuellement un dépôt, mais je voudrais avoir un dépôt dans a, et comprennent toute l'histoire au sein c.

Je suis sûr qu'il y a un moyen de faire cela, peut-être avec git filter-branch? Je ne veux pas utiliser de sous-modules, je voudrais avoir un seul dépôt à la fin.

Répondre

2

Vous avez le choix:

Vous pouvez simplement déplacer la structure actuelle dans ce qui sera la nouvelle structure. Ensuite, déplacez le repo entier d'un niveau. git add -A va ajouter tous les changements qui est un tas de suppressions et de nouveaux ajouts de fichiers. git status les montrera comme déplacés. Chaque objet est stocké une fois, quel que soit le chemin sur lequel il se trouve donc ce ne sera pas une opération coûteuse. Ce serait l'option la plus simple. À ce moment, vous pouvez également mettre dans les autres répertoires de haut niveau.

alors que dans c:

mkdir b 
cd b 
mkdir c 
mv <all other objects from top level> c 
git add -A 
git commit -m "moved everything" 
mv c a 
# clean up 

git déterminera le fait qu'un fichier a été déplacé si vous faites et vous aider à se confond.

Ou, vous pouvez pouvez utiliser la branche de filtre pour modifier l'historique si vous le souhaitez, mais tous vos commits auront SHA1s différents. Cela peut être indésirable.

+0

Ceci est une solution simple et intelligente au problème. Il reste toujours avec le problème que les chemins historiques ne sont pas précis (ce qui peut être changé avec la commande 'filter-branch' fournie par @Tobu), mais l'histoire est linéaire et intuitive quant à l'évolution du repo. Merci! – englebip

+0

Quelques remarques concernant les commandes ci-dessus: 1) les trois premières pourraient me fusionner dans 'mkdir -p b/c', puis changer la destination de' mv b/c'; 2) ne pas être (stupidement) tenté comme je devais le faire pour cette dernière commande 'mv * b/c'; vous copiez récursivement 'b/c/b/c/b/c ...' jusqu'à remplir votre disque dur. – englebip

3

Ce dont vous avez besoin est de créer votre nouveau référentiel externe et de fusionner le référentiel interne en utilisant une fusion de sous-arborescence. There's a quick HOWTO at the bottom of this page.. Vous devez temporairement déplacer c en dehors de a/b, ces instructions supposent que l'arbre c n'existe pas encore à son emplacement final.


Si vous voulez faire c sont imbriqués dans son histoire passée (et sont d'accord avec modifiées sha1s), utilisez un filtre-branche à la place (credit):

git filter-branch --index-filter \ 
    'git ls-files -s | sed "s#\t#&a/b/c/#" | 
      GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ 
        git update-index --index-info && 
    mv -T "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' -- --all 
+0

Cette solution permettra de préserver les SHA1 de de vos commits existants, mais tous les commits existants auront toujours la structure de l'arbre que vous avez aujourd'hui. À partir du point de fusion, votre structure arborescente reflétera le repo plus profond que vous souhaitez. Si vous êtes heureux d'avoir une structure d'arbre peu profonde dans l'histoire, alors c'est probablement la façon dont vous voulez vous y prendre. –

+0

Cela fonctionne presque parfaitement, sauf pour le commentaire de @Kevin.En effet, c'est ce qui se passe avec l'histoire. Ce n'est pas une affaire énorme, mais comment pourrais-je changer le chemin des commits fusionnés? Pour terminer, voici ce que j'ai utilisé: 'git remote add c_new -f ../c_repo; git read-tree - préfixe = b/c/-u c_new/master; git commit -m 'Fusionner b/c en un'; git pull -s sous-arbre c_new master; git distant rm c_new ' – englebip

+0

sha1s va changer. Filtrer la branche n'est pas quelque chose que je recommanderais sur un repo qui se trouve au milieu d'un projet. Je réserve ceci pour les cas rares où je commence un nouveau projet d'un vieux. –

0

Un simple mv ne fonctionnerait-il pas? Tout le «c» apparaîtrait simplement comme un changement de nom.

Quelque chose comme ceci: (s'il vous plaît ne pas couper et coller exactement comme je n'ai pas essayé .. juste obtenir l'essentiel ..)

cp -r /someroot/a/b/c /tmp/tmproot/c # make a full backup of the given repository 
rm -Rf /someroot/a/b/c     # completely remove c, leaving only a/b 
mv -r /someroot/a /tmp/tmproot  # moves a/b to the repository 
cd /tmp/tmproot 
git mv -r c a/b       # git-moves c into a/b, so all history of c is retained 

maintenant votre répertoire/tmp/tmproot devrait avoir un/b/c avec l'histoire de c retenu

rm /someroot 
mv -Rf /tmp/tmproot /someroot    # replace the old rep with your new one 

ajouter maintenant tout et engager

+0

C'est en effet une bonne idée, et très semblable à @ Adam. J'ai essayé celui-là, et ça a bien marché. Merci! – englebip