Je voudrais renommer / déplacer un sous-arbre de projet dans Git en le déplaçant de
/project/xyz
à
/components/xyz
Si j'utilise un plain git mv project components
, alors tout l'historique des validations pour le xyz project
est perdu. Y a-t-il un moyen de faire bouger cela de telle sorte que l'histoire soit maintenue?
git mv
: stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mvRéponses:
Git détecte les renommages plutôt que de persister l'opération avec la validation, que vous utilisiez
git mv
oumv
non.La
log
commande prend un--follow
argument qui continue l'historique avant une opération de renommage, c'est-à-dire qu'elle recherche un contenu similaire en utilisant l'heuristique:http://git-scm.com/docs/git-log
Pour rechercher l'historique complet, utilisez la commande suivante:
la source
git config alias.logf "log --follow"
et à simplement écriregit logf ./path/to/file
.Il est possible de renommer un fichier et de conserver l'historique intact, bien que cela entraîne le changement de nom du fichier tout au long de l'historique du référentiel. C'est probablement seulement pour les amateurs de git-log obsessionnels, et a de sérieuses implications, y compris celles-ci:
Maintenant, puisque vous êtes toujours avec moi, vous êtes probablement un développeur solo renommant un fichier complètement isolé. Déplaçons un fichier en utilisant
filter-tree
!Supposons que vous allez déplacer un fichier
old
dans un dossierdir
et donnez-lui le nomnew
Cela pourrait être fait avec
git mv old dir/new && git add -u dir/new
, mais cela brise l'histoire.Au lieu:
va refaire chaque commit dans la branche, exécutant la commande dans les ticks pour chaque itération. Beaucoup de choses peuvent mal tourner lorsque vous faites cela. Normalement, je teste pour voir si le fichier est présent (sinon il n'est pas encore là pour se déplacer), puis j'effectue les étapes nécessaires pour chausse-pied l'arbre à mon goût. Ici, vous pouvez parcourir les fichiers pour modifier les références au fichier, etc. Assommez-vous! :)
Une fois terminé, le fichier est déplacé et le journal est intact. Vous vous sentez comme un pirate ninja.
Aussi; Le répertoire mkdir n'est nécessaire que si vous déplacez le fichier vers un nouveau dossier, bien sûr. L' if évitera la création de ce dossier plus tôt dans l'historique que votre fichier n'existe.
la source
--index-filter
for renames sera beaucoup plus rapide car l'arborescence n'aura pas à être récupérée et réintégrée à chaque commit.--index-filter
agit directement sur chaque index de commit.Non.
La réponse courte est NON . Il n'est pas possible de renommer un fichier dans Git et de se souvenir de l'historique. Et c'est une douleur.
La rumeur veut que
git log --follow
--find-copies-harder
cela fonctionne, mais cela ne fonctionne pas pour moi, même s'il n'y a aucun changement dans le contenu du fichier et que les déplacements ont été effectués avecgit mv
.(Initialement, j'ai utilisé Eclipse pour renommer et mettre à jour des packages en une seule opération, ce qui peut avoir gêné Git. Mais c'est une chose très courante à faire.
--follow
Semble fonctionner si seulement unmv
est effectué, puis uncommit
et lemv
n'est pas trop loin.)Linus dit que vous êtes censé comprendre l'ensemble du contenu d'un projet logiciel de manière holistique, sans avoir besoin de suivre les fichiers individuels. Eh bien, malheureusement, mon petit cerveau ne peut pas faire ça.
C'est vraiment ennuyeux que tant de gens aient répété sans réfléchir la déclaration selon laquelle Git suit automatiquement les mouvements. Ils ont perdu mon temps. Git ne fait rien de tel. De par sa conception (!) Git ne suit pas du tout les mouvements.
Ma solution consiste à renommer les fichiers à leur emplacement d'origine. Modifiez le logiciel pour l'adapter au contrôle de source. Avec Git, vous semblez juste avoir besoin de "git" correctement la première fois.
Malheureusement, cela casse Eclipse, qui semble utiliser
--follow
.git log --follow
parfois, n'affiche pas l'historique complet des fichiers avec des historiques de changement de nom compliqués, même s'il legit log
fait. (Je ne sais pas pourquoi.)(Il y a des hacks trop intelligents qui reviennent en arrière et recommencent du vieux travail, mais ils sont plutôt effrayants. Voir GitHub-Gist: emiller / git-mv-with-history .)
la source
vous montrera l'historique à travers les renommage.
la source
git mv
essentiellement ungit rm && git add
. Il existe des options telles que-M90
/--find-renames=90
pour considérer un fichier à renommer lorsqu'il est identique à 90%.Je fais:
la source
-A
plutôt le comportement de ? Encore une fois, voir ici: git-scm.com/docs/git-addgit add -u
. Les documents Git ont tendance à être inutiles et sont le dernier endroit où je voudrais regarder. Voici un article affichégit add -u
en action: stackoverflow.com/a/2117202 .Non (8 ans plus tard, Git 2.19, Q3 2018), car Git détectera le renommage du répertoire , et cela est désormais mieux documenté.
Voir commit b00bf1c , commit 1634688 , commit 0661e49 , commit 4d34dff , commit 983f464 , commit c840e1a , commit 9929430 (27 juin 2018) et commit d4e8062 , commit 5dacd4a (25 juin 2018) par Elijah Newren (
newren
) .(Fusionné par Junio C Hamano -
gitster
- en commit 0ce5a69 , 24 juil.2018 )Cela est maintenant expliqué dans
Documentation/technical/directory-rename-detection.txt
:Exemple:
Mais ce sont bien d'autres cas, comme:
Pour simplifier la détection de renommage de répertoire, ces règles sont appliquées par Git:
une couple de règles de base limite lorsque la détection de renommage de répertoire s'applique:
Vous pouvez voir de nombreux tests dans
t/t6043-merge-rename-directories.sh
, qui soulignent également que:la source
Objectif
git am
Limitation
Sommaire
git log --pretty=email -p --reverse --full-index --binary
cat extracted-history | git am --committer-date-is-author-date
1. Extraire l'historique au format e-mail
Exemple: l' histoire Extrait du
file3
,file4
etfile5
Définir / nettoyer la destination
Extraire l'historique de chaque fichier au format email
Malheureusement option
--follow
ou--find-copies-harder
ne peut pas être combinée avec--reverse
. C'est pourquoi l'historique est coupé lorsque le fichier est renommé (ou lorsqu'un répertoire parent est renommé).Historique temporaire au format e-mail:
Dan Bonachea suggère d'inverser les boucles de la commande de génération de journaux git dans cette première étape: plutôt que d'exécuter git log une fois par fichier, exécutez-le exactement une fois avec une liste de fichiers sur la ligne de commande et générez un seul journal unifié. De cette façon, les validations qui modifient plusieurs fichiers restent une seule validation dans le résultat, et toutes les nouvelles validations conservent leur ordre relatif d'origine. Notez que cela nécessite également des modifications à la deuxième étape ci-dessous lors de la réécriture des noms de fichiers dans le journal (désormais unifié).
2. Réorganisez l'arborescence des fichiers et mettez à jour les noms de fichiers
Supposons que vous souhaitiez déplacer ces trois fichiers dans cet autre référentiel (il peut s'agir du même référentiel).
Réorganisez donc vos fichiers:
Votre historique temporaire est maintenant:
Modifiez également les noms de fichiers dans l'historique:
3. Appliquer une nouvelle histoire
Votre autre dépôt est:
Appliquer des validations à partir de fichiers d'historique temporaires:
--committer-date-is-author-date
conserve les horodatages de validation d'origine (commentaire de Dan Bonachea ).Votre autre dépôt est maintenant:
Utilisez
git status
pour voir le nombre de commits prêts à être poussés :-)Astuce supplémentaire: vérifiez les fichiers renommés / déplacés dans votre référentiel
Pour répertorier les fichiers renommés:
Plus de personnalisations: vous pouvez exécuter la commande à l'
git log
aide des options--find-copies-harder
ou--reverse
. Vous pouvez également supprimer les deux premières colonnes en utilisantcut -f3-
et en accueillant le motif complet '{. * =>. *}'.la source
J'ai suivi ce processus en plusieurs étapes pour déplacer le code vers le répertoire parent et conserver l'historique.
Étape 0: création d'une «historique» de branche à partir de «maître» pour la conservation
Étape 1: utilisé l' outil git-filter-repo pour réécrire l'historique. Cette commande ci-dessous a déplacé le dossier «FolderwithContentOfInterest» à un niveau supérieur et modifié l'historique de validation correspondant
Étape 2: à ce moment, le référentiel GitHub a perdu son chemin de référentiel distant. Ajout d'une référence à distance
Étape 3: extraire des informations sur le référentiel
Étape 4: connectez la branche locale perdue à la branche d'origine
Étape 5: résoudre le conflit de fusion pour la structure de dossiers si vous y êtes invité
Étape 6: Poussez !!
Remarque: L'historique modifié et le dossier déplacé semblent déjà avoir été validés.
enter code here
Terminé. Le code se déplace vers le répertoire parent / souhaité en gardant l'historique intact!
la source
Bien que le cœur de Git, la plomberie Git ne garde pas la trace des renommages, l'historique que vous affichez avec le journal Git "porcelaine" peut les détecter si vous le souhaitez.
Pour une
git log
utilisation donnée, l'option -M:Avec une version actuelle de Git.
Cela fonctionne aussi pour d'autres commandes
git diff
.Il existe des options pour rendre les comparaisons plus ou moins rigoureuses. Si vous renommez un fichier sans apporter de modifications importantes au fichier en même temps, il est plus facile pour Git log et ses amis de détecter le renommage. Pour cette raison, certaines personnes renomment des fichiers dans un commit et les modifient dans un autre.
L'utilisation du processeur a un coût chaque fois que vous demandez à Git de trouver où les fichiers ont été renommés, que vous l'utilisiez ou non, et quand, c'est à vous de décider.
Si vous souhaitez que votre historique soit toujours signalé avec la détection de renommage dans un référentiel particulier, vous pouvez utiliser:
Les fichiers se déplaçant d'un répertoire à un autre sont détectés. Voici un exemple:
Veuillez noter que cela fonctionne chaque fois que vous utilisez diff, pas seulement avec
git log
. Par exemple:À titre d'essai, j'ai apporté une petite modification dans un fichier dans une branche de fonctionnalité et je l'ai validée, puis dans la branche principale, j'ai renommé le fichier, validé, puis j'ai apporté une petite modification dans une autre partie du fichier et je l'ai validé. Lorsque je suis allé dans la branche de fonctionnalité et que j'ai fusionné à partir de master, la fusion a renommé le fichier et fusionné les modifications. Voici la sortie de la fusion:
Le résultat a été un répertoire de travail avec le fichier renommé et les deux modifications de texte effectuées. Il est donc possible pour Git de faire la bonne chose malgré le fait qu'il ne suit pas explicitement les renommages.
Il s'agit d'une réponse tardive à une ancienne question, donc les autres réponses peuvent être correctes pour la version Git à l'époque.
la source
Créez d'abord un commit autonome avec juste un renommage.
Ensuite, toute modification éventuelle du contenu du fichier est placée dans la validation distincte.
la source
Pour renommer un répertoire ou un fichier (je ne connais pas grand-chose aux cas complexes, il peut donc y avoir quelques mises en garde):
Pour renommer un répertoire dans des fichiers qui le mentionnent (il est possible d'utiliser des rappels, mais je ne sais pas comment):
expressions.txt
est un fichier rempli de lignes commeliteral:OLD_NAME==>NEW_NAME
(il est possible d'utiliser RE avec Pythonregex:
ou glob avecglob:
).Pour renommer un répertoire dans les messages de commit:
Les expressions régulières de Python sont également prises en charge, mais elles doivent être écrites en Python, manuellement.
Si le référentiel est d'origine, sans télécommande, vous devrez ajouter
--force
pour forcer une réécriture. (Vous pouvez créer une sauvegarde de votre référentiel avant de le faire.)Si vous ne souhaitez pas conserver les références (elles seront affichées dans l'historique des branches de Git GUI), vous devrez les ajouter
--replace-refs delete-no-add
.la source
Déplacez simplement le fichier et mettez en scène avec:
Avant de valider, vous pouvez vérifier l'état:
Cela montrera:
J'ai testé avec Git version 2.26.1.
Extrait de la page d'aide de GitHub .
la source
Je fais déplacer les fichiers et ensuite
qui met dans la zone de saturation tous les fichiers supprimés / nouveaux. Ici, git se rend compte que le fichier est déplacé.
Je ne sais pas pourquoi mais cela fonctionne pour moi.
la source