101 votes

git ne détecte pas les renommages

Une branche ( refactoringBranch ) a fait l'objet d'une restructuration complète de son répertoire. Les fichiers ont été déplacés de façon désordonnée, mais le contenu a été préservé.

J'ai essayé de fusionner : git merge --no-ff -Xrename-threshold=15 -Xpatience -Xignore-space-change refactoringBranch

git status montre une reconnaissance du renommage d'environ la moitié des fichiers. Mais sur les 10000 fichiers du projet, la moitié n'a pas été reconnue comme déplacée.

Un exemple serait :

# On branch master
# Changes to be committed:

#   deleted:    404.php
#   new file:   public_html/404.php
    ...
#   deleted:    AnotherFile.php
#   new file:   public_html/AnotherFile.php
    ...
#   renamed:    contracts/css/view.css -> public_html/contracts/css/view.css

Des suggestions ?


Préhistoire

Le remaniement a été effectué en dehors de git. J'ai fait ce qui suit :

  1. Créé le refactoringBranch provenant de master .
  2. Déposé la structure modifiée à l'intérieur de la refactoringBranch ce qui signifie que j'avais mes changements dans un autre répertoire et que je les ai simplement copiés-collés sur mon dépôt git.
  3. J'ai tout ajouté et validé, puis j'ai essayé de fusionner.

C'est ce que j'ai fait :

git checkout -b refactoringBranch
cp -R other/place/* ./
git add . -A
git commit -a -m "blabla"
git checkout master
git merge --no-ff -Xrename-threshold=15 -Xpatience -Xignore-space-change refactoringBranch

Le problème se pose sur le git add . -A étape probablement. Parce que si la détection des renommages est correcte ici, je suppose que la fusion se fera sans problème.

0 votes

J'ai vérifié, à l'aide d'un outil externe, la similitude entre 404.php en master et public_html/404.php sur refactoringBranch semblait être 95.37% .

1 votes

De quel outil externe s'agit-il ? Avez-vous testé différents seuils de renommage avec quelque chose comme git diff -M90% --stat master refactoringBranch (en essayant avec différentes valeurs au lieu de 90%) ?

0 votes

L'outil a été php.net/similar_text . Dans ma commande de fusion, j'utilise un seuil aussi bas que 15 %. Je m'attendrais à ce qu'elle soit acceptée.

135voto

andrhamm Points 668

OS X tient compte de la casse, mais n'y est pas sensible. Git est sensible à la casse. Si vous avez changé le nom d'un fichier et que le seul changement était un changement de casse, renommez le fichier comme il était avant, puis utilisez la fonction git mv pour renommer à la place.

12 votes

Une solution très simple qui a résolu mon problème. Pour ceux qui sont curieux de savoir ce que fait l'instruction "git mv oldfilename newfilename", voici le lien vers la documentation : kernel.org/pub/software/scm/git/docs/git-mv.html . En fait, il met automatiquement à jour l'index pour les anciens et les nouveaux fichiers. Nous vous remercions de votre attention.

0 votes

Cette opération échoue avec "permission refusée" si vous modifiez le nom d'un dossier pour qu'il soit identique, à l'exception des majuscules. Cependant, stackoverflow.com/a/14580217/5593532 permet de contourner ce problème (en changeant d'abord de nom intermédiaire).

5 votes

Il n'est pas nécessaire de "renommer le fichier à l'identique", il suffit de "renommer" le fichier à l'identique. git mv oldcase newcase œuvre.

54voto

John Bartholomew Points 3712

Détection des renommages :

Mon hypothèse la plus probable est que la détection des renommages échoue en raison du très grand nombre de candidats. Le code source git est un peu difficile à suivre par endroits, mais il semble qu'il y ait des limites codées en dur utilisées dans des étapes de recherche particulières de l'algorithme de détection des renommages (cf. diffcore-rename.c ), ainsi que la limite configurable du nombre maximal de paires à examiner (clés de configuration diff.renameLimit y merge.renameLimit ). Cela peut faire échouer la détection, même si vous avez fixé la limite configurée à un niveau suffisamment élevé. La limite configurable elle-même est fixée dans la plage [1, 32767].

Vous pouvez peut-être contourner ce problème en effectuant d'abord une étape de restructuration : déplacez les fichiers avec git mv sans modifier le contenu, afin de les faire correspondre à la nouvelle mise en page, validez cette étape sur une nouvelle branche, puis remplacez-la par votre version finale, qui ne devrait comporter que des modifications de contenu et aucun renommage. Renommages sans changement de contenu pourrait être détecté de manière plus fiable. Cela n'est pratique que si la restructuration que vous avez effectuée est assez simple, et je ne suis pas certain que cela résoudra les échecs de détection des renommages.

Alternativement, vous pouvez peut-être diviser les changements en commits séparés avec des groupes de fichiers simples, de sorte qu'il y ait moins de candidats pour la détection des renommages dans chaque commit.

Fusionner :

Malheureusement, en basant la nouvelle branche sur master, vous donnez à git des informations incorrectes sur la fusion. Indépendamment du fait que les renommages soient correctement détectés ou non, lorsque la branche nouvellement créée sera fusionnée avec master, elle écrasera tout ce qui se trouve dans master, car du point de vue de git, il n'y a pas de modifications dans master qui n'aient pas déjà été incluses dans la nouvelle branche.

0 votes

Discussion similaire avec des paramètres configurables dans git disponible ici

52voto

Alex Onozor Points 574

Voici un moyen parfait pour permettre à git de savoir que vous renommez un fichier.

git mv old-file-name.ts new-file-name.ts

Ensuite, git reprendra ces changements.

Profitez-en.

3 votes

Est-il possible d'appliquer cette mesure après que les renommages ont déjà été effectués ?

1 votes

Qu'est-ce que .ts et pourquoi cela fonctionne-t-il ? Si vous voulez dire simplement git mv file1 file2, alors cela ne fonctionne pas si vous faites beaucoup de changements dans les fichiers.

31voto

BoD Points 3490

Au lieu de git status Essayez. git commit --dry-run -a il détecte mieux les renommages.

8 votes

Pourquoi ces points en moins ? Cette technique a bien fonctionné dans mon cas, une explication serait la bienvenue.

6 votes

Vous n'avez rien expliqué. Vous utilisez --dry-run ce qui signifie seulement un commit "simulé". Cette technique est déjà utilisée par op (juste sans --dry-run).

0 votes

Résultats identiques avec git 2.8.0.

13voto

Pooky Points 465

Vous pouvez envisager d'utiliser git mv à la place : https://www.kernel.org/pub/software/scm/git/docs/git-mv.html

D'après mon expérience, il est beaucoup plus fiable.

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