È possibile che git-merge ignori le differenze di fine riga?


150

È possibile git mergeignorare le differenze di fine riga?

Forse sto facendo la domanda sbagliata ... ma:

Ho provato a usarlo config.crlf inputma le cose sono diventate un po ' confuse e fuori controllo, specialmente quando l'ho applicato dopo il fatto .

Per prima cosa, l'applicazione di questa configurazione dopo il fatto non sembra influire sui file che sono stati impegnati nel repository prima di applicare questa opzione. Un'altra cosa è che all'improvviso tutti i commit ora comportano la conversione in LF di molti fastidiosi messaggi di avviso sul CRLF.

Ad essere sincero, non mi interessa davvero quale linea venga usata, preferisco personalmente lo stile Unix \n, ma qualunque cosa. Tutto quello che mi interessa, è per git mergeessere un po 'più intelligente e ignorare le differenze nei finali di linea.

A volte ho due file identici, ma git li contrassegnerebbe come in conflitto (e il conflitto è l' intero file) semplicemente perché usano un carattere di fine riga diverso.

Aggiornare:

Ho scoperto che git diffaccetta --ignore-space-at-eolun'opzione, sarebbe possibile git mergeutilizzare anche questa opzione?


28
Oh vorrei. Questa cosa di fine riga in git è totalmente interrotta
1800 INFORMAZIONI

Appena aggiunto un caso di prova che illustra che lo strumento di unione di terze parti ignorerà lo stile eol durante un'unione
VonC

Quindi, per chiarire (da ciò che posso determinare): non c'è modo di ottenere git per ignorare i CR ma lamentarsi di tutti gli altri spazi bianchi finali?
Stephen,

Assicurati di dare un'occhiata alla risposta qui sotto sugit config merge.renormalize true
qneill

Risposte:


115

Aggiornamento 2013:

Le versioni git più recenti autorizzano l'uso di unisci con strategia recursivee opzione strategia ( -X):

git merge -s ricorsive -Xignore-space-at-eol

Ma usare " -Xignore-space-change" è anche una possibilità

  • Fab-V menziona di seguito :
    git merge master -s ricorsivo -X rinormalizza
    
    

jakub.g commenta inoltre che le strategie funzionano anche con la raccolta delle ciliegie :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Funziona molto meglio di ignore-all-space.


Risposta originale (maggio 2009)

La patch per ignorare lo stile EOL è stato proposto nel giugno 2007 , ma solo preoccupazioni git diff --ignore-space-at-eole non git merge.

Al momento, la domanda è stata posta:

Dovrebbe --ignore-space-at-eolessere un'opzione per git-merge?
Le fusioni sono importanti per questa funzionalità.
Quali sono le semantiche di un'unione risolta automaticamente con quelle opzioni in effetti: vengono utilizzate solo per il rilevamento della ridenominazione o, ad esempio, non contrassegniamo i conflitti solo con le modifiche agli spazi bianchi? E se non lo facciamo, quale versione accettiamo automaticamente?

Julio C Hamano non era esattamente entusiasta:

Questo è certamente allettante, ma sospetto che dovrebbe essere lasciato ai round successivi.
Ho il sospetto che introdurrebbe un concetto di due diversi tipi di diff, uno da elaborare meccanicamente (cioè usare in unione con "git-merge-recursive", e applicare con "git-am"), e un altro da ispezionare da gli umani a capire.
Spesso può essere utile deviare l'input per quest'ultimo caso, anche se l'output dal confronto dei file di input mung potrebbe non essere prontamente utilizzabile per applicazioni meccaniche.

L'idea generale, quando si tratta git merge, è di fare affidamento sullo strumento di unione di terze parti.

Ad esempio, ho impostato DiffMerge come strumento per l'unione di Git, impostando un set di regole che consente a quello strumento di unione di ignorare eol per un determinato tipo di file.


Installazione su Windows, con MSysGit1.6.3, per sessione DOS o Git bash, con DiffMerge o KDiff3:

  • imposta una directory nel tuo PERCORSO (qui:) c:\HOMEWARE\cmd.
  • aggiungi in quella directory lo script merge.sh (wrapper per il tuo strumento di unione preferito)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Dichiara il tuo wrapper di unione per Git

Comandi Git config:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Verificare che autoCRLF sia falso

config git a livello di sistema:

git config ---system core.autoCRLF=false
  • Prova che, quando due linee sono identiche (ma i loro caratteri eol), sia DiffMerge che KDiff3 ignoreranno quelle linee durante l'unione.

Script DOS (nota: il comando dos2unix viene da qui e viene utilizzato per simulare uno stile eol Unix. Tale comando è stato copiato nella directory menzionata all'inizio di questa risposta.):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

A questo punto (premendo "return"), si apriranno DiffMerge o KDiff3 e vedrai di persona quali linee vengono effettivamente unite e quali linee vengono ignorate.

Attenzione : il file dei risultati sarà sempre in modalità eol di Windows (CRLF) con DiffMerge ...
KDiff3 offre di salvare in un modo o nell'altro.


Grazie per il suggerimento! Meld e FileMerge in Mac sembrano essere anche ottime app.
Léo Léopold Hertz 준영

1
Per informazioni, le strategie funzionano anche con la raccolta delle ciliegie : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (funziona molto meglio di ignore-all-space)
jakub.g

1
@ jakub.g buon punto! L'ho incluso nella risposta per una maggiore visibilità.
VonC,

98

Cercavo la stessa risposta e ho scoperto questo

Unione di rami con attributi di checkin / checkout diversi

Se sono stati aggiunti attributi a un file che causa la modifica del formato del repository canonico per quel file, come l'aggiunta di un filtro clean / smudge o di attributi text / eol / ident, l'unione di qualsiasi cosa in cui l'attributo non è in atto causerebbe normalmente conflitti di unione .

Per evitare questi inutili conflitti di unione, si può dire a git di eseguire un check-out virtuale e il check-in di tutte e tre le fasi di un file quando si risolve un'unione a tre vie impostando la variabile di configurazione merge.renormalize. Ciò impedisce alle modifiche causate dalla conversione del check-in di causare conflitti di unione spuria quando un file convertito viene unito a un file non convertito.

Finché una "sfumatura → pulita" produce lo stesso output di una "pulita" anche sui file che sono già macchiati, questa strategia risolverà automaticamente tutti i conflitti relativi al filtro. I filtri che non agiscono in questo modo possono causare ulteriori conflitti di unione che devono essere risolti manualmente.

Quindi eseguire questo comando in qualsiasi repository farà il trucco:

git config merge.renormalize true

20
Questo merita ora di essere la risposta predefinita. Molto è cambiato da quando la domanda è stata posta per la prima volta, la gestione di git di questo è ora integrata con merge.renormalize come dici tu.
Anton I. Sipos,

Questo è semplicemente fantastico ... mi salva la giornata
matthaeus,



4

Quello che ho fatto è stato lasciare tutto come predefinito (ad esempio autocrlf = true), toccare tutti i file (find. -Exec touch {} \;), lasciare che git li vedesse come "modificati" e ripristinarli, e finire. Altrimenti o sarai sempre afflitto da messaggi fastidiosi o differenze sorprendenti, o dovrai disattivare tutte le funzionalità di spazio bianco di git.

Perderai le informazioni sulla colpa, ma è meglio farlo prima piuttosto che dopo :)


4

"git merge -Xrenormalize" funziona come un incantesimo.




0

Adesso mi sembra che il modo migliore sia normalizzare le terminazioni di linea su entrambi i rami (e il commit) prima di unirle.

Ho cercato su Google "converti crlf in lf" e ho trovato questo come primo risultato:
http://stahlforce.com/dev/index.php?tool=remcrlf

L'ho scaricato e utilizzato, sembra uno strumento piacevole.

>sfk remcr . .py

Assicurati di specificare una directory e un tipo di file (ad esempio .py), altrimenti potrebbe provare a rovinare il contenuto della .gitdirectory!


0

AFAICT, (non l'ho provato) potresti usare git diffper confrontare il ramo che vuoi unire al comune antenato, quindi applicare i risultati con git apply. Entrambi i comandi hanno --ignore-whitespaceopzioni per ignorare la fine della linea e gli errori di spazio bianco.

Sfortunatamente, se la patch non si applica in modo pulito, l'intera operazione viene interrotta. Non è possibile correggere i conflitti di unione. C'è --rejectun'opzione per lasciare hunk non raggiungibili nei .rejfile, il che aiuta, ma non è lo stesso di avere i conflitti di unione mostrati in un file.


-1

Dopo aver letto Risolvi conflitti di unione: Forza sovrascrivi tutti i file

Ho finalmente risolto la mia versione di questo problema. Stavo cercando di estrarre gli aggiornamenti dal repository upstream, ma quello attuale presentava problemi relativi a CRLF e non è stato possibile unirli di conseguenza. Va notato che non avevo CAMBIAMENTI LOCALI di cui dovevo preoccuparmi. I seguenti passaggi hanno risolto il mio problema:

Secondo le istruzioni di github sulla sincronizzazione delle forcelle ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    La mia comprensione limitata di git mi dice che questo sta facendo quello che voglio: ridisegnare il fork (senza modifiche effettive non confermate) per ottenere tutte le modifiche apportate alla sorgente a monte. Secondo la pagina di origine, questo passaggio normalmente non dovrebbe essere richiesto, ma il problema CRLF lo rendeva necessario.

  3. git merge upstream/master

  4. git push

1
Ti rendi conto che git reset --hard upstream/masterbutta via la tua filiale locale e la punta a upstream/master, facendo git merge upstream/masteruna no-op?
Christoffer Hammarström,

-1

tuttavia suggerisco di utilizzare uno strumento come sed per ottenere la terminazione di riga corretta e quindi i file diff. Ho trascorso un paio d'ore in diversi progetti con vari finali di linea.

Il modo migliore era:

  1. copia solo i file di progetto (ometti .gitdirectory) in un'altra directory, crea un repository al suo interno, quindi aggiungi i file e li commetti (dovrebbe trovarsi sul ramo master nel nuovo repository).
  2. copia i file dal secondo progetto nella stessa cartella, ma ad esempio un altro ramo dev( git checkout -b dev), esegui il commit dei file su questo ramo ed esegui (se il primo progetto è nel master): git diff master..dev --names-only per vedere solo i nomi dei file modificati
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.