Comment puis-je déplacer un répertoire et des fichiers dans un sous-répertoire avec l'historique de validation?
Par exemple:
Structure du répertoire source: [project]/x/[files & sub-dirs]
Structure du répertoire cible: [project]/x/p/q/[files & sub-dirs]
Pour ajouter à bmargulies 's comment , la séquence complète est la suivante:
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 voir un aperçu du déménagement:
git mv -n x/* x/p/q
Si vous utilisez bash, vous pouvez éviter le problème d'essayer de déplacer un dossier vers lui-même en utilisant un glob étendu tel que so (en utilisant le
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 sur Windows avec Cygwin.
Je viens de me rendre compte que l’exempleshopt -s extglob
Était mauvais, alors mon chemin n’est peut-être pas nécessaire, mais j’utilise typiquement zsh au lieu de bash et il n’a pas la commandeshopt -s extglob
(bien que je sois sûr qu'il existe une alternative), cette approche devrait donc fonctionner pour tous les shells (en remplaçant dansmkdir
etrmdir
de votre shell s'il est particulièrement étranger)
Comme alternative, spanky mentionne dans les commentaires l'option -k
De git mv
:
Ignorer le déplacement ou renommer les actions qui pourraient conduire à une condition d'erreur.
git mv -k * target/
Cela éviterait l'erreur "can not move directory into itself
".
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 car ils appartenaient auparavant à x
, mais ils appartiennent maintenant à x/p/q
parce que le projet a évolué de cette façon.
Parfois, cependant, il existe une raison de déplacer des fichiers vers un sous-répertoire tout au long de l'historique d'un projet. Par exemple, si les fichiers ont été placés quelque part par erreur et que des commits supplémentaires ont été effectués depuis, mais que les commits intermittents n'ont aucun sens si les fichiers sont mal placés. Si tout cela se passait dans une branche locale, nous voulons nettoyer le désordre avant de pousser.
La question dit "avec l'histoire de commettre", ce que j'interprèterais comme une réécriture de l'histoire exactement de cette façon. 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
_ sous-répertoire tout au long de l’histoire.
Veuillez noter que le résultat ne doit pas être transmis à un serveur public si la réécriture touche les validations qui ont déjà été envoyées auparavant.
Je peux voir que c'est une vieille question, mais je me sens toujours obligé de répondre à ma solution actuelle au problème, que j'ai tirée de l'un des exemples de git book . Au lieu d'utiliser un inefficace --tree-filter
Je déplace les fichiers directement sur l'index avec un --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 de l'historique de validation dans un cas particulier. Si vous déplacez des fichiers dans des sous-répertoires: souvenez-vous d'échapper le caractère/dans les chemins d'accès 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 à la racine 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
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 indiquant qu’un dossier ne pouvait pas être déplacé sur 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, ceci ignorera les tous mouvements qui pourraient conduire à une condition d'erreur. Vous voudrez donc probablement vérifier que tout a bien fonctionné après le déplacement et avant une validation.