2011-09-11 2 views
23

Ma situation était, j'ai un git repo converti de SVN en HG en GIT, et je voulais extraire un seul fichier source. J'ai également eu des caractères étranges comme aÌ (une incompatibilité d'encodage Unicode ä) et des espaces dans les noms de fichiers. Cela ne semble pas particulièrement facile, et c'est la raison pour laquelle je vais répondre à ma propre question malgré de nombreuses questions similaires concernant git [index-filtre | subdirectory-filter | filtre-arbre], comme je devais utiliser tous les précédents pour y parvenir! Donc, la question est: "Comment puis-je extraire un fichier d'un dépôt et le placer à la racine du nouveau repo?"Comment extraire un fichier avec l'histoire de commit d'un repo git avec index-filter & co

+0

Pourquoi voulez-vous extraire seul fichier à partir du repo? – svick

+1

C'est tout ce dont j'ai besoin. Et btw, http://stackoverflow.com/questions/5998987/splitting-a-set-of-files-within-a-git-repo-into-the-own-repository-preserving n'est pas un clone de n'importe quel sous-répertoire- question de filtrage. L'extraction de fichiers nécessite à la fois l'étape --subdirectory-filter et un --index-filter ou --tree-filter. – peterhil

+1

Ou plutôt tout ce que je veux, parce que je vais faire un paquet du fichier unique qui fournit un trie. Je veux aussi l'utiliser dans d'autres projets, et publier dans Github et j'ai du code dans le repo que je ne veux pas faire open source (du moins pour l'instant). – peterhil

Répondre

10

D'abord une note rapide, que même un sort comme dans un commentaire sur Splitting a set of files within a git repo into their own repository, preserving relevant history

SPELL='git ls-tree -r --name-only --full-tree "$GIT_COMMIT" | grep -v "trie.lisp" | tr "\n" "\0" | xargs -0 git rm --cached -r --ignore-unmatch' 
git filter-branch --prune-empty --index-filter "$SPELL" -- --all 

ne va pas aider avec les fichiers nommés comme imaging/DrinkkejaI<0300>$'\302\210'.txt_74x2032.gif. La pièce aI<0300>$'\302\210' était une seule lettre: ä.

Ainsi, afin d'extraire un seul fichier, en plus de filtrer branche aussi je devais faire:

git filter-branch -f --subdirectory-filter lisp/source/model HEAD 

Vous pouvez également utiliser --tree-filtre: (le test est nécessaire, parce que le fichier était dans un autre répertoire plus tôt, voir How can I move a directory in a Git repo for all commits?)

MV_FILTER='test -f source/model/trie.lisp && mv ./source/model/trie.lisp . || echo "Nothing to do."' 
git filter-branch --tree-filter $MV_FILTER HEAD --all 

Pour voir tous les noms d'un fichier ont eu, utilisez:

git log --pretty=oneline --follow --name-only git-path/to/file | grep -v ' ' | sort -u 

Comme décrit à http://whileimautomaton.net/2010/04/03012432

également suivre les étapes sur la suite:

$ git reset --hard 
$ git gc --aggressive 
$ git prune 
$ git remote rm origin # Otherwise changes will be pushed to where the repo was cloned from 
+3

Je ne suis pas sûr de savoir comment suivre ces instructions, le texte de cette réponse semble poser plusieurs voies possibles. Je ne vois aucune procédure. – ThorSummoner

+0

Peut-être que vous devriez voir la documentation git sur la commande filter-branch et sur l'historique de réécriture: - http://git-scm.com/docs/git-filter-branch - http://git-scm.com/ book/fr/v2/Git-Tools-Réécriture-Historique – peterhil

8

Notez que les choses deviennent beaucoup plus facile si vous combinez cela avec l'étape supplémentaire de déplacer le fichier souhaité (s) dans un nouveau répertoire.

Cela peut être un cas d'utilisation assez courant (par exemple déplacer le fichier unique souhaité vers le répertoire racine).
je l'ai fait (en utilisant git 1.9) comme celui-ci (premier déplacement du fichier (s), puis en supprimant le vieil arbre):

git filter-branch -f --tree-filter 'mkdir -p new_path && git mv -k -f old_path/to/file new_path/' 
git filter-branch -f --prune-empty --index-filter 'git rm -r --cached --ignore-unmatch old_path' 

Vous pouvez même utiliser facilement des caractères génériques pour les fichiers désirés (sans déconner avec grep -v).

Je penserais que ceci ('mv' et 'rm') pourrait également être fait dans une branche de filtre mais il n'a pas fonctionné pour moi.

Je ne l'ai pas essayé avec des caractères étranges mais j'espère que cela aide de toute façon. Rendre les choses plus faciles semble toujours être une bonne idée pour moi.

Indice:
Cette action prend beaucoup de temps sur les gros dépôts. Donc, si vous voulez faire plusieurs actions (comme obtenir un tas de fichiers et les réorganiser dans 'new_path/subdirs'), c'est une bonne idée de faire la partie 'rm' dès que possible pour obtenir un arbre plus petit et plus rapide.

+0

Je l'ai également essayé sur Ubuntu 12.04 et git 1.7.x avec les résultats suivants: * le problème de permission refusée apparaît aussi sur Ubuntu * git 1.7.x didn ' Je fais bien avec les commandes que j'ai mentionnées ci-dessus (comme 1 seul fichier correspondant a toujours été renommé dans le répertoire où il devrait être déplacé. Donc je recommande git 1.9.x que je cours sur ma machine Windows – Roman

+0

retravaillé mon poste parce que la plupart de mes problèmes semblent provenir de mes compétences bash inexistantes -> utiliser '&&' au lieu de '|' pour combiner les commandes maintenant – Roman

+0

La première étape ne marche pas k pour moi en git 2.2.1. Il n'y a pas de changement au repo. – xixixao

21

Une plus rapide et plus facile à comprendre filtre qui fait la même chose:

git filter-branch --index-filter ' 
         git read-tree --empty 
         git reset $GIT_COMMIT -- $your $files $here 
       ' \ 
     -- --all -- $your $files $here 
+0

Celui-ci est le meilleur – podarok

+0

Cela a fonctionné parfaitement pour moi. J'ai ajouté un argument '--prune-empty' pour supprimer les validations vides. –

+0

@AaronJensen Les '--all - $ your $ files $ here' de la dernière ligne sont passés à la' git rev-list' que 'filter-branch' exécute, donc les branches de la branche filter du filtre ont déjà été élaguées . C'est beaucoup plus rapide que de faire charger inutilement l'index par le filtre-branche et d'exécuter le filtre et de créer de nouveaux arbres et un commit avant de tout jeter pour les commits qui n'ont pas touché ces fichiers. Pourtant, ça ne fait pas de mal de l'ajouter. – jthill

Questions connexes