git add –interactive “Votre morceau modifié ne s’applique pas”

J’essaie d’utiliser git add --interactive pour append de manière sélective des modifications à mon index, mais je reçois continuellement le message “Votre morceau modifié ne s’applique pas. Modifier à nouveau …”. Je reçois ce message même si je choisis l’option e et que je sauvegarde / ferme immédiatement mon éditeur. En d’autres termes, sans modifier le morceau, le patch ne s’applique pas.

Voici l’exemple exact que j’utilise (j’essaie de mettre en place une petite démo):

Fichier d’origine:

 first change second change off branch third change off branch second change third change fourth change 

Nouveau fichier:

 Change supporting feature 1 first change second change off branch third change off branch second change third change fourth change bug fix 1 change supporting feature 1 

J’essaie de montrer comment utiliser git add --interactive pour append uniquement la ligne “bug fix 1” à l’index. En cours d’exécution interactive sur le fichier, je choisis le mode de patch. Il me présente

 diff --git a/newfile b/newfile index 6d501a3..8b81ae9 100644 --- a/newfile +++ b/newfile @@ -1,6 +1,9 @@ +Change supporting feature 1 first change second change off branch third change off branch second change third change fourth change +bug fix 1 +change supporting feature 1 

Je réponds avec split, suivi de “non” pour appliquer le premier morceau. Le deuxième morceau, j’essaie d’éditer. Au départ, j’ai essayé de supprimer la ligne du bas – cela ne fonctionnait pas. Laisser le gros morceau seul ne fonctionne pas non plus, et je n’arrive pas à comprendre pourquoi.

Pour cet exemple particulier, vous devez modifier les numéros de ligne dans le morceau. Changer la ligne:

 @@ -1,6 +2,8 @@

de sorte qu’il lit à la place:

 @@ -2,7 +2,8 @@

Est-ce comme dans ce post git-add ?

L’édition manuelle du morceau est extrêmement puissante, mais aussi un peu compliquée si vous ne l’avez jamais fait auparavant.
La chose la plus importante à garder à l’esprit: le diff est toujours mis en retrait avec un caractère en plus de toute autre indentation.
Le personnage peut être soit:

  • un espace (indique une ligne inchangée),
  • a - indiquant que la ligne a été supprimée,
  • ou a + indiquant que la ligne a été ajoutée.

Rien d’autre. Ce doit être un espace, un – ou un +. Autre chose et vous aurez des erreurs
(il n’y a pas de caractère pour une ligne modifiée, car celles-ci sont gérées en supprimant l’ancienne ligne et en ajoutant la nouvelle ligne).

Étant donné que vous avez ouvert le diff dans votre éditeur de texte préféré (vous avez configuré Git pour utiliser votre éditeur de texte préféré, non?), Vous pouvez faire ce que vous voulez, à condition que le diff résultant soit correctement appliqué.

Et c’est là que réside l’astuce. Si vous ne l’avez jamais fait auparavant, Git vous dira “Votre morceau édité ne s’applique pas. Modifiez-le?” Si souvent, vous commencez à vous haïr pour votre incapacité à comprendre cela , même si cela semble si facile (ou Git parce qu’il ne peut pas comprendre ce que vous voulez).

Une chose qui m’a fait trébucher assez souvent, c’est que j’avais oublié le retrait d’un personnage.
Je marquerais une ligne avec un – pour être supprimé, mais dans la plupart des éditeurs de texte qui insèrent un - , cela ne remplace pas l’espace qui existait auparavant. Cela signifie que vous ajoutez un espace supplémentaire à la ligne entière, ce qui signifie que l’algorithme diff ne peut pas trouver / correspondre à la ligne dans le fichier d’origine, ce qui signifie que Git va vous crier dessus .

L’autre chose est que le diff doit encore avoir du sens. “Sens” signifie qu’il peut être appliqué proprement. Exactement comment vous créez un diff sensible semble être un peu un art sombre (du moins pour moi en ce moment), mais vous devez toujours garder à l’esprit comment le fichier d’origine ressemblait, puis planifier vos-et-s en conséquence. Si vous modifiez assez souvent vos pièces, vous finirez par comprendre.

Voir aussi ce commit sur git add -p .

Bien sûr, je suis en retard pour cela, mais je voulais néanmoins mentionner pour le compte rendu que cette question a été discutée l’année dernière sur la liste de diffusion de git et que peu de choses ont changé depuis.

Ce problème particulier provient de la division et de la tentative de modification du même morceau. L’parsing, telle que publiée par Jeff King, du problème sous-jacent est essentiellement la suivante:

Hm. OK je vois. Le “fait cela diff appliquer” contrôle alimente les deux parties du patch divisé à git-apply. Mais bien sûr, la deuxième partie ne s’appliquera jamais correctement, car son contexte chevauche la première partie, mais ne la prend pas en compte.

Faire la vérification avec juste le patch édité fonctionnerait. Mais cela ne tient pas compte du fait que votre correctif édité risque de ne pas s’appliquer à long terme, selon que vous acceptez ou non l’autre moitié du correctif partagé. Et nous ne pouvons pas encore le savoir, car l’utilisateur ne nous l’a peut-être pas dit (il aurait pu ignorer le premier semestre, puis y revenir plus tard après l’étape de modification).

Jeff conclut son post avec une solution de contournement très pragmatique qui réussit toujours et est donc fortement recommandé:

Donc, en général, je pense que diviser et éditer le même morceau est insortingnsèquement dangereux et va entraîner ce genre de problèmes. Et parce que l’édition fournit un sur-ensemble des fonctionnalités, je pense que vous devez simplement éditer et autoriser ou non la première partie du morceau à être appliquée, selon vos préférences.

En choisissant uniquement de modifier un morceau qui n’a pas encore été divisé, vous n’aurez pas à traiter les numéros de ligne.

Lorsque vous ne souhaitez pas supprimer une ligne à mettre en attente pour suppression, comme dans

  first line -second line third line 

lorsque vous souhaitez conserver la deuxième ligne, assurez-vous de remplacer le - par un espace, plutôt que de supprimer la ligne entière (comme si vous supprimiez une ligne ajoutée). Git utilisera la ligne pour le contexte.

J’ai récemment compris en lisant ce fil comment travailler l’édition manuelle.

Le truc que j’ai utilisé était que si j’ai un problème comme celui-ci.

 + Line to add + Line to add + Line I dont want to include + Line I dont want to include 

L’astuce consiste à supprimer les deux lignes que je ne veux pas complètement rendre le résultat résultant comme ceci.

 + Line to add + Line to add 

Bien que cela soit très évident pour la plupart des gens, ce n’était pas pour moi jusqu’à aujourd’hui et j’ai pensé que je devais simplement partager mon expérience. Dites-moi s’il y a un danger pour cette méthode.

Vous pouvez modifier manuellement les numéros de ligne, ce qui est certainement utile dans certains cas. Cependant, vous auriez probablement pu éviter ce problème particulier en ne divisant PAS d’abord le morceau.

Si vous voyez que vous aurez probablement besoin d’éditer quelque chose plus tard dans le morceau que Git a choisi automatiquement, il est préférable d’éditer l’intégralité du morceau plutôt que de le diviser en deux, puis de modifier l’autre moitié. Git fera un meilleur travail pour le savoir.

Je suis venu à cette question à la recherche d’une solution au même problème, et je ne pouvais pas comprendre comment changer les numéros de ligne (comme suggéré ci-dessus) dans le morceau pour que git l’accepte dans mon cas. Cependant, j’ai trouvé une meilleure façon de le faire en utilisant git gui . Là, vous pouvez sélectionner les lignes dans le diff que vous souhaitez mettre en scène, puis cliquez avec le bouton droit de la souris et choisissez “Lignes de scène de la validation”. Je me souviens que git-cola a les mêmes fonctionnalités.

Un problème supplémentaire que j’ai eu lorsque j’ai eu cette erreur est que les fins de ligne ont changé lorsque j’ai enregistré le fichier d’édition.

J’utilisais Windows et j’utilisais Notepad pour mes modifications (enregistre uniquement avec les fins de ligne Windows). Mon code a été écrit avec Notepad ++ et je l’ai configuré pour avoir des fins de ligne de style Unix / Linux.

Lorsque j’ai changé mes parameters pour que Notepad ++ devienne l’éditeur git par défaut, j’ai pu apporter des modifications au morceau.

 git config --global core.editor "notepad++" 

Il est important de modifier également correctement l’en-tête du morceau (par exemple, @@ -1,6 +1,9 @@ ). Joaquin Windmuller révèle le secret de l’édition en tête-à-tête dans l’un de ses billets .

Les secrets de l’édition de pièces

Éditer les pièces peut être déroutant au début, les instructions que git vous donne de l’aide mais ne sont pas suffisantes pour commencer.

 # —|| # To remove '-' lines, make them ' ' lines (context). # To remove '+' lines, delete them. # Lines starting with # will be removed. # # If the patch applies cleanly, the edited hunk will immediately be # marked for staging. If it does not apply cleanly, you will be given # an opportunity to edit again. If all lines of the hunk are removed, # then the edit is aborted and the hunk is left unchanged. 

La sauce secrète c’est… compter les lignes:

  • Si vous supprimez une ligne commençant par +, soustrayez-en une au nouveau nombre de lignes (dernier chiffre de l’en-tête du morceau) .
  • Si vous supprimez une ligne commençant par – puis ajoutez-en une au nouveau nombre de lignes (dernier chiffre de l’en-tête du morceau) .
  • Ne supprimez pas les autres lignes (lignes de référence).

Cela devrait vous permettre de modifier rapidement les pièces pour sélectionner les pièces souhaitées.

Une des raisons des messages bizarres “Votre morceau édité ne s’applique pas” (probablement accompagné de quelque chose comme “erreur: fragment de patch sans en-tête à la ligne …”) pourrait être votre éditeur s’il est configuré pour supprimer les espaces blancs. Cela causerait évidemment des problèmes majeurs, car les patches encodent des lignes vides comme des lignes avec un seul espace. Tout morceau contenant des lignes vides ne s’appliquerait pas s’il était enregistré avec un tel éditeur. Donc, en réalité, tout morceau contenant des lignes vides non modifiées ne s’appliquerait pas après l’édition avec si les espaces blancs restants sont activés.