109 votes

Déplacer le fichier et le répertoire dans un sous-répertoire avec l'historique des livraisons.

Comment puis-je déplacer un répertoire et des fichiers dans un sous-répertoire avec l'historique des livraisons ?

Par exemple :

  • Structure du répertoire source : [project]/x/[files & sub-dirs]

  • Structure du répertoire cible : [project]/x/p/q/[files & sub-dirs]

111voto

VonC Points 414372

À ajouter à bmargulies 's commentaire la séquence complète est :

mkdir -p x/p/q      # make sure the parent directories exist first
git mv x/* x/p/q    # move folder, with history preserved
git commit -m "changed the foldername x into x/p/q"

Essayez-le d'abord pour avoir un aperçu du mouvement :

git mv -n x/* x/p/q

Wolfgang commentaires :

Si vous utilisez bash, vous pouvez éviter le problème d'essayer de déplacer un dossier dans son propre dossier en utilisant un glob étendu comme suit (en utilisant le site shopt intégré ):

shopt -s extglob; git mv !(folder) folder

Captain Man rapports dans les commentaires à faire :

mkdir temp 
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;

Le contexte :

Je suis sous Windows avec Cygwin.
Je viens de réaliser que j'ai fait le shopt -s extglob L'exemple est faux, donc ma méthode n'est peut-être pas nécessaire, mais j'utilise généralement zsh au lieu de bash, et il n'y avait pas la commande shopt -s extglob (bien que je sois sûr qu'il existe une alternative), cette approche devrait donc fonctionner avec tous les shells (en utilisant le paramètre mkdir y rmdir si elle est particulièrement étrangère)


Comme alternative, fessée mentionne dans les commentaires el -k option de git mv :

Sautez les actions de déplacement ou de renommage qui conduiraient à une condition d'erreur.

git mv -k * target/

Cela permettrait d'éviter le " can not move directory into itself " erreur.

53voto

PiQuer Points 735

Git fait un très bon travail pour suivre le contenu même s'il est déplacé, donc git mv est clairement la voie à suivre si vous déplacez des fichiers parce qu'ils appartenaient à la section x mais maintenant ils appartiennent à x/p/q parce que le projet a évolué de cette façon.

Parfois, cependant, il y a une raison de déplacer des fichiers vers un sous-répertoire tout au long de l'histoire d'un projet. Par exemple, si les fichiers ont été placés quelque part par erreur et que d'autres commits ont été faits depuis, mais que les commits intermittents n'ont même pas de sens avec les fichiers au mauvais endroit. Si tout cela s'est produit sur une branche locale, nous voulons nettoyer le désordre avant de pousser.

La question précise "avec l'historique de commit", ce que j'interpréterais comme une réécriture de l'historique dans ce sens précis. Cela peut être fait avec

git filter-branch --tree-filter "cd x; mkdir -p p/q; mv [files & sub-dirs] p/q" HEAD

Les fichiers apparaissent alors dans le p/q tout au long de l'histoire.

Le filtre en arbre est bien adapté aux petits projets, son avantage est que la commande est simple et facile à comprendre. Pour les grands projets, cette solution n'est pas très adaptée, si les performances sont importantes, il faut envisager d'utiliser un filtre d'indexation comme indiqué dans la section cette réponse .

Veuillez noter que le résultat ne doit pas être poussé vers un serveur public si la réécriture touche des commits qui ont déjà été poussés auparavant.

14voto

peroyhav Points 161

Je vois qu'il s'agit d'une vieille question, mais je me sens quand même obligé d'y répondre avec ma solution actuelle au problème, que j'ai dérivée d'un des exemples de l'ouvrage intitulé git book . Au lieu d'utiliser un système inefficace --tree-filter Je déplace les fichiers directement sur l'index Avec une --index-filter .

git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/^<old_location>/<new_location>/"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

Il s'agit d'une spécialisation de l'un des exemples du livre J'ai également utilisé le même exemple pour renommer en masse des fichiers dans l'historique des livraisons dans un cas particulier. si vous déplacez des fichiers dans des sous-répertoires : n'oubliez pas d'échapper le caractère / dans les chemins avec un \ pour que la commande sed fonctionne comme prévu.

Exemple :

Project Directory
                 |-a
                 |  |-a1.txt
                 |  |-b
                 |  |  |-b1.txt

pour déplacer le répertoire b vers le Root du projet :

git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/a\/b\//b\//"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

Résultat :

Project Directory
                 |-a
                 |  |-a1.txt
                 |
                 |-b
                 |  |-b1.txt

8voto

Jeremy Hutchins Points 159

La commande git mv est le moyen le plus simple. Cependant, au moins sur ma machine Linux, je devais fournir le drapeau -k pour éviter de recevoir une erreur en retour indiquant qu'un dossier ne peut pas être déplacé dans lui-même. J'ai pu effectuer l'action en utilisant...

mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit

En guise d'avertissement, cela permettra d'ignorer todos qui conduirait à une condition d'erreur, donc vous voudrez probablement vérifier que tout a fonctionné correctement après le déplacement et avant une livraison.

1voto

tomsv Points 2565

Voici une méthode alternative si, pour une raison ou une autre, vous ne souhaitez pas utiliser la commande git mv :

  • Assurez-vous que vous n'avez pas de modifications non validées.

    git status

  • Il suffit de déplacer le dossier qui contient le dossier .git vers le nouveau dossier :

    mkdir nouveau_dossier mv ancien_dossier nouveau_dossier

  • Ensuite, déplacez le fichier .git old_folder du dossier déplacé vers le dossier de base :

    mv nouveau_dossier/ancien_dossier/.git nouveau_dossier/

  • Ensuite, mettez en scène et livrez tous les changements détectés (énumérés comme l'ajout de fichiers à leur nouvel emplacement et leur suppression de leur ancien emplacement).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X