web-dev-qa-db-fra.com

git, moyen sûr de déplacer / renommer des fichiers tout en conservant l'historique

Je sais qu'il y a "beaucoup" de questions existantes qui se ressemblent, alors permettez-moi de les résumer avant de poser les miennes.

La réponse à la première, je ne suis pas d'accord, car je l'ai déjà fait auparavant. La réponse à la seconde est la raison pour laquelle je pose cette question. C'est à dire.,

J'ai trouvé que je fais git mv tout le temps, mais parfois il est traité comme déplacer/renommer, et parfois il est traité comme supprimer + ajouter. Ainsi, je veux savoir comment je peux toujours en faire un mouvement/renommer?

Prenons celui-ci comme exemple, en bas, nous pouvons voir plusieurs cas de déplacement/renommage, comme easygenapi/tf-varcaser.go → tf-varcaser.go. Notez que ces mouvements sont à travers/entre les dossiers ! C'est-à-dire que je l'ai fait !

Mais il existe de nombreux autres cas git mv ont été traités comme suppression + ajout, apparaissant dans le même journal des modifications. Encore une fois, je fais git mv tout le temps. Pourquoi git se comporte-t-il différemment?

Existe-t-il un moyen sûr de déplacer/renommer les fichiers git tout en conservant l'historique?

16
xpt

tl; dr; non

Version plus longue: D'après mon expérience, git est très bon pour détecter le mouvement/renommer tant que le fichier n'est pas modifié. Git utilise l'heuristique pour tenter de localiser le mouvement. Il peut être trompé en ayant plusieurs fichiers trop similaires ou si le fichier a été modifié pendant le déplacement, ce qui le rend trop différent de son original.

La meilleure façon que j'ai trouvée pour ce faire est de faire des validations en plusieurs étapes, en séparant tous vos mouvements dans un commit, suivi des changements dans un autre. Par exemple...

git mv foo.txt bar.txt
git commit

... modify bar.txt ...

git add bar.txt
git commit

Cela ne garantira pas que votre déménagement est détecté correctement, car il peut toujours être confus lorsqu'il y a plusieurs candidats. Cependant, cela a très bien fonctionné pour moi et capture la majorité des cas.

24
Kevin Burdett

Git ne suit pas les renommages. Période. Il ne suit pas non plus les ajouts. Ou supprime. Ou diffs. Ou des patchs. Ou se déplace. Ou toute sorte de changement, vraiment.

Git est basé sur un instantané. Chaque commit enregistre un instantané de l'ensemble du projet. C'est tout. Comment cet instantané est apparu, Git ne sait ni ne se soucie.

Les différences, les correctifs, les ajouts, les suppressions, les déplacements, les renommages, etc. sont affichés par divers outils de visualisation, qui les déduisent après coup à l'aide d'heuristiques (ce qui est une autre façon de dire "deviner"). Parfois, ils peuvent deviner correctement ce que vous avez fait, et parfois non. Cela n'a pas d'importance, cependant, car ce n'est que de la visualisation, cela ne fait en aucun cas partie de l'histoire, de la forme ou de la forme.

La plupart des outils utilisent une certaine forme de métrique de similitude et infèrent qu'un changement de nom s'est produit si deux fichiers ont une similitude supérieure à un certain seuil. Dans certains outils, ce seuil est configurable. Dans certains outils, même l'algorithme est configurable. (Un exemple légèrement lié: git diff vous permet de choisir entre différents algorithmes pour déduire les différences dans fichiers.)

Étant donné que Git n'enregistre pas les modifications, il est possible d'ajouter de nouvelles modifications dans les versions ultérieures des outils de visualisation qui peuvent déduire ces modifications d'anciennes validations qui ont été enregistrées avant même que les nouveaux outils qui comprennent de nouveaux types de modifications n'aient été écrits. Imaginez, par exemple, un outil qui comprend la syntaxe et la sémantique du langage de programmation que vous utilisez. Il pourrait visualiser un certain commit non pas comme un tas de fichiers ayant chacun quelques lignes modifiées, mais comme un seul changement qui renomme un sous-programme et met à jour chaque site d'appel (c'est-à-dire Rename Method Refactoring).

Les renommages en sont un bon exemple. L'heuristique de détection de renommage et les mesures de similitude utilisées par git log --follow, par exemple, ont été améliorés plusieurs fois. IIRC, au début, les renoms n'étaient pas du tout déduits, cette capacité a été ajoutée plus tard. Cela n'aurait tout simplement pas été possible si Git avait enregistré des modifications au lieu de clichés.

13
Jörg W Mittag