git add --interactive "Il tuo pezzo modificato non si applica"


85

Sto cercando di utilizzare git add --interactiveper aggiungere selettivamente alcune modifiche al mio indice, ma ricevo continuamente il messaggio "Il tuo pezzo modificato non si applica. Modifica di nuovo ...". Ricevo questo messaggio anche se scelgo l'opzione e e salvo / chiudo immediatamente il mio editor. In altre parole, senza modificare affatto il pezzo, la patch non si applica.

Ecco l'esempio esatto che sto usando (sto cercando di mettere insieme una piccola demo):

File originale:

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

Nuovo file:

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

Sto cercando di mostrare come utilizzare git add --interactiveper aggiungere solo la riga "bug fix 1" all'indice. Eseguendo l'aggiunta interattiva sul file, scelgo la modalità patch. Mi presenta

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

Rispondo con split, seguito da "no" per applicare il primo pezzo. Il secondo pezzo, provo a modificare. Inizialmente ho provato a cancellare la linea di fondo, ma non ha funzionato. Anche lasciare il pezzo da solo completamente non funziona e non riesco a capire perché.


Una buona cosa da verificare qui è che non stai aggiungendo -all'inizio delle righe che non esistono nel file per cominciare; è un diff e non può eliminare righe che non sono già presenti. Quindi se una riga nel diff inizia con +e la cambi in -git diventa WTF? perché ora la riga contrassegnata per la rimozione non esiste per cominciare (invece quella riga è stata contrassegnata per l'aggiunta, e quando una riga contrassegnata per l'aggiunta è contrassegnata per la rimozione git non può rimuovere una riga che non è già nel file) .
leeand00

1
Controlla anche le terminazioni di riga (LF, CRLF) nel mio caso non si applicava per un LF invece di CRLF!
Alberto Rivelli

Risposte:


37

Per questo particolare esempio, è necessario modificare i numeri di riga nel blocco. Cambia la linea:

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

in modo che invece legga:

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

16
Dopo un po 'di ricerca, ho scoperto che quelle righe mostrano "intervallo da file" e "intervallo a file". Non capisco davvero la logica dietro la modifica di 1 in 2. L'ho provato e funziona, ma non capisco perché il "intervallo da file" cambia. Il file originale è lo stesso, sia che applichi l'intera patch o solo il pezzo modificato. Puoi chiarire ulteriormente o indicarmi un riferimento di discesa sul formato diff unificato. Non sono riuscito a trovarne uno.
Josh

9
@Josh: stackoverflow.com/questions/2529441/... può aiutare, anche se non ho ricevuto tutto gli hunk formato unificato. @William +1
VonC

5
@ Josh: esaminandolo sembra che possa essere un bug. Dopo aver modificato l'hunk, git tenta di verificare la patch controllando che tutti gli hunk vengano applicati (questo potrebbe essere eccessivo). Sfortunatamente, in questo caso, ciò significa che il blocco precedente (che non stai applicando) viene controllato e che c'è qualche sovrapposizione che fa fallire git apply --check. Non conosco una soluzione elegante; git potrebbe fare la cosa giusta essendo eccessivamente cauto qui.
William Pursell

22
Maggiori informazioni sulla modifica dei numeri di linea per favore? Perché dobbiamo farlo? E come? Cosa significa ogni numero?
Bill

4
@ WilliamPursell quali versioni di git? Sono passato a un nuovo computer e ho eseguito git v2.17.0 e improvvisamente le mie modifiche alle patch non sono più valide.
Dennis

105

È come in questo post git-add ?

La modifica manuale del pezzo è immensamente potente, ma anche un po 'complicata se non l'hai mai fatto prima.
La cosa più importante da tenere a mente: il diff è sempre rientrato con un carattere in aggiunta a qualsiasi altra rientranza presente.
Il personaggio può essere:

  • uno spazio (indica una linea invariata),
  • a -che indica che la linea è stata rimossa,
  • o un +che indica che la linea è stata aggiunta.

Nient'altro. Deve essere uno spazio, un - o un +. Qualsiasi altra cosa e otterrai errori
(non ci sono caratteri per una riga modificata, poiché questi vengono gestiti rimuovendo la vecchia riga e aggiungendo quella modificata come nuova).

Dato che hai il diff aperto nel tuo editor di testo preferito (hai configurato Git per utilizzare il tuo editor di testo preferito, giusto?), Puoi fare quello che vuoi, purché ti assicuri che il diff risultante si applichi in modo pulito.

E qui sta il trucco. Se non l'hai mai fatto prima, Git ti dirà "Il tuo pezzo modificato non si applica. Modificare di nuovo?" così spesso, inizierai a odiarti per la tua incapacità di capirlo , anche se sembra così facile (o Git perché non riesce a capire cosa vuoi).

Una cosa che mi ha fatto inciampare abbastanza spesso è stata che ho dimenticato il trattino di un carattere.
Contrassegnerei una riga con un - da rimuovere, ma nella maggior parte degli editor di testo che inserisce a -, non sovrascrive lo spazio che c'era prima. Ciò significa che stai aggiungendo uno spazio aggiuntivo all'intera riga, il che a sua volta significa che l'algoritmo diff non riesce a trovare / abbinare la riga nel file originale, il che a sua volta significa che Git ti sgriderà .

L'altra cosa è che il diff deve ancora avere un senso. "Sense" significa che può essere applicato in modo pulito. Il modo esatto in cui crei un diff sensibile sembra essere un po 'un'arte oscura (almeno per me in questo momento), ma dovresti sempre tenere a mente come appariva il file originale, quindi pianificare i tuoi -s e + di conseguenza. Se modifichi i tuoi fusti abbastanza spesso, alla fine capirai come funziona.

Vedi anche questo commit su git add -p .

Ortomala Lokni 's risposta si riferisce a Joaquín Windmüller post sul blog ' selettivamente selezionare cambiamenti di impegnarsi con git (o Imma modificare il vostro pezzo) '

Invece di contare le righe, ciò che Git vorrebbe fare è unire hunk sovrapposti (quando ne viene modificato uno) prima di applicare detto hunk modificato.
Questo è stato discusso a metà del 2018 e eviterebbe scenari come:

se dividi un pezzo, modifica il primo sotto-pezzo, trasformando una riga di contesto finale in una cancellazione, quindi se provi a mettere in scena il secondo sotto-pezzo, fallirà.


5
Grazie per il link, ma l'avevo già visto. Non stavo aggiungendo / lasciando una riga aggiuntiva. Il problema era nei numeri di riga, ma ancora non capisco la soluzione.
Josh

9
Non stavo sostituendo un "-" cancellato con uno spazio vuoto - rovinando così il rientro. Grazie!!
pedorro

Assicurati solo di non fraintendere la parte dello spazio vuoto. Ho pensato che tutte le linee invariate dovessero essere solo una linea con un nero - invece del semplice carattere di rientro ... Ho avuto un'ora di "pezzo modificato non si applica" finché non ho capito perché: - /
oligofren

@oligofren Non sono sicuro di capirti: cosa hai dovuto fare per applicare il tuo pezzo modificato?
VonC

1
@ VonC: prima ho pensato di dover cambiare - foo in "(solo uno spazio vuoto, non" uno spazio vuoto e l'intera riga "). Mi ci è voluto un po 'per capire che avrebbe dovuto essere "foo".
oligofren

48

Ovviamente sono in ritardo per questo, ma comunque volevo menzionare per la cronaca che questo problema è stato discusso l'anno scorso sulla mailing list di git e sembra che da allora non sia cambiato molto.

Questo particolare problema deriva dalla divisione e dal tentativo di modificare lo stesso pezzo. L'analisi, come originariamente pubblicata da Jeff King, del problema sottostante è essenzialmente:

Hm. Va bene, ho capito. Il controllo "does this diff apply" alimenta entrambe le parti della patch divisa a git-apply. Ma ovviamente la seconda parte non verrà mai applicata correttamente, perché il suo contesto si sovrappone alla prima parte, ma non ne tiene conto.

Fare il controllo con solo la patch modificata funzionerebbe. Ma ciò non tiene conto del fatto che la patch modificata potrebbe potenzialmente non essere applicata a lungo termine, a seconda che tu accetti o meno l'altra metà della patch divisa. E non possiamo ancora saperlo, perché l'utente potrebbe non avercelo detto (potrebbe aver saltato la prima metà e poi tornarci più tardi dopo la fase di modifica).

Jeff conclude il suo post con una soluzione molto pragmatica che riesce sempre, ed è quindi altamente raccomandato:

Quindi, in generale, penso che dividere e modificare lo stesso pezzo sia intrinsecamente pericoloso e porterà a questo tipo di problemi. E poiché l'editing fornisce un superset delle funzionalità, penso che dovresti semplicemente modificare e consentire l'applicazione della prima parte del pezzo o meno a seconda delle tue preferenze.

Scegliendo solo di modificare un pezzo non precedentemente diviso, non dovrai occuparti dei numeri di riga.


6
Grazie, questo è davvero molto più semplice che armeggiare con i numeri di riga.
michiakig

3
Questo era il mio problema. Avevo bisogno che il mio pezzo fosse più piccolo. Hai eseguito una divisione in interattivo. La divisione non era quello che volevo, quindi ho deciso di provare a modificare manualmente. Ho continuato a ricevere l'errore. Ricominciato, ha funzionato al primo tentativo.
Kyle

Questa è la migliore risposta in questo thread. Non dividere e modificare. Basta modificare.
Dr_Zaszuś

Nel mio caso, un ulteriore problema proveniva dalle terminazioni di riga di Windows mostrate come ^Mnel file diff. Dopo aver salvato il file con finali CR, la patch di modifica interattiva è stata completata!
Dr_Zaszuś

Grazie, questo ha funzionato per me. Ho dovuto lavorare su un pezzo enorme, quindi l'ho diviso e tutto si è rotto. Mantenerlo non diviso ha fatto funzionare tutto bene.
Matthias Fischer

16

Quando non si desidera eliminare una riga che è stata pianificata per l'eliminazione, come in

 first line
-second line
 third line

dove vuoi mantenere la seconda riga, assicurati di sostituire il -con uno spazio, piuttosto che eliminare l'intera riga (come faresti per sbarazzarti di una riga aggiunta). Git userà la riga per il contesto.


1
Non mi era chiaro, pensavo che Git mi stesse dicendo di rendere la linea uno spazio unico.
JackHasaKeyboard

15

È importante anche modificare correttamente l'intestazione dell'hunk (ad esempio @@ -1,6 +1,9 @@). Joaquin Windmuller rivela il segreto della modifica dell'intestazione di un pezzo in uno dei suoi post sul blog .

I segreti della modifica dei fusti

La modifica degli hunk può creare confusione all'inizio, le istruzioni fornite da git ti aiutano ma non sono sufficienti per iniziare.

# —||

# 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 salsa segreta è ... contare le righe:

  • Se rimuovi una riga che inizia con +, allora sottrai uno al nuovo conteggio delle righe (ultima cifra dell'intestazione del pezzo) .
  • Se rimuovi una riga che inizia con - aggiungine una al nuovo conteggio delle righe (ultima cifra dell'intestazione del pezzo) .
  • Non rimuovere le altre linee (linee di riferimento).

Questo dovrebbe consentirti di modificare rapidamente gli hunk per selezionare le parti che desideri.


1
C'è un modo per automatizzare la modifica dell'intestazione dell'hunk o configurare git per determinare i conteggi di riga appropriati?
Dennis

Probabilmente puoi scrivere il tuo editor preferito per automatizzarlo. Forse ci sono già alcuni plugin per questo, ma questo dipende dall'editor.
Ortomala Lokni

14

Recentemente ho capito leggendo questo thread come eseguire l'editing manuale.

Il trucco che ho usato è stato che se ho un diff come:

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

Il trucco è rimuovere completamente le due linee che non voglio, facendo sembrare il diff risultante:

+ Line to add
+ Line to add

Anche se questo è molto probabilmente ovvio per la maggior parte delle persone, non è stato per me fino ad oggi e ho pensato che avrei dovuto condividere la mia esperienza. Per favore dimmi se c'è qualche pericolo con questo metodo.


2
Non posso ringraziarti abbastanza! Stavo cercando di cambiare la +in a ' 'per almeno un'ora.
soumer

Sai, la follia è fare la stessa cosa e aspettarsi un risultato diverso. L'ho detto a me stesso per 20 minuti prima di capire che dovevo solo cancellare :)
solidak

Questa dovrebbe essere la risposta. Bello e semplice, grazie!
xPeaWhyTee

7

Puoi modificare manualmente i numeri di riga, che è sicuramente utile in alcuni casi. Tuttavia, probabilmente avresti potuto evitare questo particolare problema NON dividendo prima il pezzo.

Se vedi che probabilmente dovrai modificare qualcosa in seguito nell'hunk che Git ha scelto automaticamente, è meglio modificare solo l'intero pezzo piuttosto che dividere, mettere in scena metà e quindi modificare l'altra metà. Git farà un lavoro migliore per capirlo.


6

Sono arrivato a questa domanda cercando una soluzione allo stesso problema e non sono riuscito a capire come modificare i numeri di riga (come suggerito sopra) nell'hunk per fare in modo che git lo accetti nel mio caso. Ho trovato un modo molto migliore per farlo usando git guiperò. Lì puoi selezionare le linee nel diff che vuoi mettere in scena, quindi fare clic con il tasto destro e scegliere "Stage lines from commit". Ricordo che anche git-cola ha la stessa funzionalità.


Questa dovrebbe davvero essere la risposta. git-colasembra funzionare su Linux, Windows e MacOS.
leeand00

5

Un ulteriore problema che ho avuto quando ho ricevuto questo errore è stato che le terminazioni di riga sono cambiate quando ho salvato il file di modifica.

Stavo usando Windows e utilizzavo Blocco note per le mie modifiche (salva solo con le terminazioni di riga di Windows). Il mio codice è stato scritto con Notepad ++ e l'ho impostato per avere terminazioni di riga in stile Unix / Linux.

Quando ho cambiato le mie impostazioni per avere Notepad ++ come editor git predefinito, sono stato in grado di apportare le mie modifiche al pezzo.

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

1
Questo ha funzionato per me. Ma avevo bisogno del percorso completo per Notepad ++ e ci è voluto un po 'per farlo bene: git config --global core.editor '"C:/Program\ Files\ \(x86\)/Notepad++/notepad++.exe"' (adattalo in base a dove notepad ++ è installato sul tuo PC)
Annabel

1
Lo stesso problema per me. Era il Blocco note a causare problemi. Dopo aver cambiato il mio editor predefinito su Notepad ++, tutto ha ripreso a funzionare.
Johnny Oshika

4

Un motivo per strani messaggi "Il tuo pezzo modificato non si applica" (probabilmente accompagnato da qualcosa come "errore: frammento di patch senza intestazione alla riga ...") potrebbe essere il tuo editor se è configurato per rimuovere gli spazi vuoti finali. Questo ovviamente causerebbe grossi problemi poiché le patch codificano le righe vuote mentre le righe con uno spazio qualsiasi pezzo contenente righe vuote non sarebbero applicabili se salvate con un tale editor. Quindi, in effetti, qualsiasi pezzo contenente righe vuote non modificate non si applicherebbe dopo la modifica con se l'eliminazione degli spazi vuoti finali è attiva.


0

Cordiali saluti, stavo ricevendo un errore leggermente correlato ... quando ho aggiunto la patch seguendo le istruzioni suggerite sopra ... Tuttavia, non mostrava alcun errore. Lo ricevevo ripetutamente chiedendomi di mettere in scena lo stesso pezzo ... Ho notato che stavo eseguendo una versione precedente di Vim 7.4 ... Ho aggiornato vim e ora funziona come previsto. Spero che questo aiuti qualcuno ..

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.