Funzionamento delle conversioni di fine riga con git core.autocrlf tra diversi sistemi operativi


220

Ho letto molte domande e risposte diverse su Stack Overflow e documentazione git su come funziona l' impostazione core.autocrlf .

Questa è la mia comprensione da ciò che ho letto:

I client Unix e Mac OSX (pre-OSX utilizzano CR) utilizzano i finali di linea LF.
I client Windows utilizzano i finali di linea CRLF.

Quando core.autocrlf è impostato su true sul client, il repository git archivia sempre i file nel formato di fine riga LF e le terminazioni di riga nei file sul client vengono convertite avanti e indietro al check out / commit per i client (ovvero Windows) che usano non -LF finali di linea, indipendentemente dal formato in cui si trovano i file dei finali di linea sul client (questo non è d'accordo con la definizione di Tim Clem - vedi aggiornamento sotto).

Ecco una matrice che tenta di documentare lo stesso per le impostazioni 'input' e 'false' di core.autocrlf con punti interrogativi in ​​cui non sono sicuro del comportamento di conversione di fine riga.

Le mie domande sono:

  1. Quali dovrebbero essere i punti interrogativi?
  2. Questa matrice è corretta per i "punti non di domanda"?

Aggiornerò i punti interrogativi dalle risposte man mano che il consenso sembra formarsi.

                       valore core.autocrlf
            vero input false
-------------------------------------------------- --------
commettere | convertire? ?
nuovo | in LF (convertire in LF?) (nessuna conversione?)

commettere | convertire in ? no
esistente | Conversione LF (convertire in LF?)

checkout | convertire in ? no
esistente | Conversione CRLF (nessuna conversione?)

Non sto davvero cercando opinioni su pro e contro delle varie impostazioni. Sto solo cercando dati che chiariscano come aspettarsi che git funzioni con ciascuna delle tre impostazioni.

-

Aggiornamento del 17/04/2012 : dopo aver letto l'articolo di Tim Clem collegato da JJD nei commenti, ho modificato alcuni dei valori nei valori "sconosciuti" nella tabella sopra, oltre a cambiare "checkout esistente | vero per convertire in CRLF anziché convertirlo in client ". Ecco le definizioni che fornisce, che sono più chiare di qualsiasi cosa abbia visto altrove:

core.autocrlf = false

Questo è il valore predefinito, ma la maggior parte delle persone è incoraggiata a cambiarlo immediatamente. Il risultato dell'uso di falso è che Git non fa mai casino con le terminazioni di riga nel tuo file. Puoi archiviare i file con LF o CRLF o CR o un mix casuale di questi tre e Git non se ne cura. Ciò può rendere le differenze più difficili da leggere e le fusioni più difficili. La maggior parte delle persone che lavorano in un mondo Unix / Linux usano questo valore perché non hanno problemi CRLF e non hanno bisogno che Git faccia un lavoro extra ogni volta che i file vengono scritti nel database degli oggetti o scritti nella directory di lavoro.

core.autocrlf = true

Ciò significa che Git elaborerà tutti i file di testo e si assicurerà che CRLF venga sostituito con LF durante la scrittura di quel file nel database degli oggetti e trasformerà nuovamente tutti gli LF in CRLF durante la scrittura nella directory di lavoro. Questa è l'impostazione consigliata su Windows perché garantisce che il repository possa essere utilizzato su altre piattaforme mantenendo CRLF nella directory di lavoro.

core.autocrlf = input

Ciò significa che Git elaborerà tutti i file di testo e si assicurerà che CRLF venga sostituito con LF durante la scrittura di quel file nel database degli oggetti. Tuttavia, non farà il contrario. Quando si leggono i file di nuovo dal database degli oggetti e li si scrive nella directory di lavoro, avranno ancora LF per indicare la fine della riga. Questa impostazione viene generalmente utilizzata su Unix / Linux / OS X per impedire che i CRLF vengano scritti nel repository. L'idea è che se hai incollato il codice da un browser web e hai accidentalmente inserito i CRLF in uno dei tuoi file, Git si sarebbe assicurato che fossero sostituiti con gli LF quando scrivevi nel database degli oggetti.

L'articolo di Tim è eccellente, l'unica cosa che riesco a pensare è che manchi che il repository sia in formato LF, il che non è necessariamente vero, specialmente per i progetti solo per Windows.

Il confronto tra l'articolo di Tim e la risposta più votata fino ad oggi da jmlane mostra un perfetto accordo sulle impostazioni true e input e disaccordo su false setting.


7
Mantenere autocrlffalse sembra molto più facile;) stackoverflow.com/questions/2333424/...
VonC

@VonC: l'ho letto e penso di capirlo, ma non riesco necessariamente a fare la scelta. Lavoro con repository git che non controllo a chi richiede di impostare il valore in un certo modo.
Michael Maddox,

5
Non sarebbe bello se Windows fosse normalizzato anche a LF? Mac era CR (prima v10) ma ora è normalizzato a LF.
Brett Ryan,

3
Devo aggiungere un link al fantastico articolo di Timothy Clem - per favore leggi tutto Mind the End of Your Line .
JJD,

1
Scenario: sono uno sviluppatore Linux / Windows diviso. Uso solo editor di testo in grado di riconoscere entrambi i tipi di terminazioni di riga (IE. Vim, eclipse). Ho solo bisogno (voglio) di lavorare con file che finiscono in LF. Al momento ho core.autocrlf = input impostato nella mia configurazione globale di git. Sono bravo ad andare? Avrò mai un conflitto?
Chris,

Risposte:


128

La migliore spiegazione di come core.autocrlffunziona si trova nella pagina man di gitattributes , nella textsezione degli attributi.

Ecco come core.autocrlfsembra funzionare attualmente (o almeno dalla v1.7.2 da quello che sono a conoscenza):

  • core.autocrlf = true
    1. I file di testo estratti dal repository con solo LFcaratteri sono normalizzati CRLFnella struttura di lavoro; i file che contengono CRLFnel repository non verranno toccati
    2. I file di testo che hanno solo LFcaratteri nel repository, vengono normalizzati da CRLFa LFquando vengono ripristinati nel repository. I file che contengono CRLFnel repository verranno sottoposti a commit non toccati.
  • core.autocrlf = input
    1. I file di testo estratti dal repository manterranno i caratteri EOL originali nell'albero di lavoro.
    2. I file di testo nell'albero di lavoro con CRLFcaratteri vengono normalizzati LFquando ripristinati nel repository.
  • core.autocrlf = false
    1. core.eol detta i caratteri EOL nei file di testo dell'albero di lavoro.
    2. core.eol = nativeper impostazione predefinita, ciò significa che le EOL di Windows sono CRLFe * nix Le EOL sono LFin alberi di lavoro.
    3. Le gitattributesimpostazioni del repository determinano la normalizzazione dei caratteri EOL per il commit nel repository (l'impostazione predefinita è la normalizzazione dei LFcaratteri).

Ho appena studiato questo problema e trovo anche la situazione molto contorta. L' core.eolimpostazione ha sicuramente aiutato a chiarire come i personaggi EOL sono gestiti da Git.


3
per autocrlf = true non dovrebbe essere il seguente? I file di testo che contengono solo caratteri EOL CRLF nel repository, vengono normalizzati da CRLF a LF quando vengono ripristinati nel repository. I file che contengono LF nel repository non verranno toccati.
Piotr Lewandowski il

2
Per me, anche se autocrlf = false git stava convertendo l'EOL in CRLF. Dopo aver letto questa risposta mi sono reso conto che il mio file .gitattribute aveva text = auto set che causava il problema.
Irsis,

1
Perché core.autocrlf = false, se non ho un gitattributesfile, significa che non ci sarà normalizzazione? O significa che utilizzerà la normalizzazione predefinita?
Chin,

Il .gitattributesfile non dovrebbe avere la precedenza core.autocrlfsull'impostazione?
Qwerty il

63

La questione delle EOL nei progetti su piattaforme miste ha reso la mia vita miserabile per molto tempo. I problemi sorgono quando di solito ci sono già file con EOLs diverse e contrastanti già nel repository. Ciò significa che:

  1. Il repository può avere file diversi con EOL diverse
  2. Alcuni file nel repository potrebbero avere EOL misto, ad esempio una combinazione di CRLFe LFnello stesso file.

Come questo accada non è il problema qui, ma succede.

Ho eseguito alcuni test di conversione su Windows per le varie modalità e le loro combinazioni.
Ecco cosa ho ottenuto, in una tabella leggermente modificata:

                 | Conversione risultante quando | Conversione risultante quando
                 | commettere file con vari | verificando DA repo -
                 | EOL INTO repo e | con file misti in esso e
                 | valore core.autocrlf: | valore core.autocrlf:           
-------------------------------------------------- ------------------------------
File | vero | input | falso | vero | input | falso
-------------------------------------------------- ------------------------------
Windows-CRLF | CRLF -> LF | CRLF -> LF | così com'è | così com'è | così com'è | come è
Unix -LF | così com'è | così com'è | così com'è | LF -> CRLF | così com'è | come è
Mac -CR | così com'è | così com'è | così com'è | così com'è | così com'è | come è
Misto-CRLF + LF | così com'è | così com'è | così com'è | così com'è | così com'è | come è
Misto-CRLF + LF + CR | così com'è | così com'è | così com'è | così com'è | così com'è | come è

Come puoi vedere, ci sono 2 casi in cui la conversione avviene su commit (3 colonne a sinistra). Nel resto dei casi i file vengono impegnati così come sono.

Al checkout (3 colonne a destra), c'è solo 1 caso in cui la conversione avviene quando:

  1. core.autocrlfè true e
  2. il file nel repository ha l' LFEOL.

La cosa più sorprendente per me, e sospetto, la causa di molti problemi di EOL è che non esiste una configurazione in cui EOL misto come CRLF+ venga LFnormalizzato.

Si noti inoltre che anche i "vecchi" Mac EOL CRnon vengono mai convertiti.
Ciò significa che se uno script di conversione EOL scritto male tenta di convertire un file finale misto con CRLFs + LFs, semplicemente convertendo LFs in CRLFs, lascerà il file in modalità mista con "solitari" CRovunque sia CRLFstato convertito CRCRLF.
Git non convertirà quindi nulla, nemmeno in truemodalità, e il caos di EOL continua. Questo in realtà è successo a me e ha incasinato i miei file davvero male, dal momento che ad alcuni editor e compilatori (ad esempio VS2010) non piacciono i Mac EOL.

Immagino che l'unico modo per gestire davvero questi problemi sia di occasionalmente normalizzare l'intero repository controllando tutti i file in inputo falsemodalità, eseguendo una corretta normalizzazione e riconfermando i file modificati (se presenti). Su Windows, presumibilmente riprendi a lavorare con core.autocrlf true.


4
Ottima risposta, ma una frase con cui non posso essere d'accordo è su Windows, presumibilmente riprendere a lavorare concore.autocrlf true . Personalmente credo che inputdovrebbe essere usato sempre.
G. Demecki,

39

Le cose stanno per cambiare sul fronte della "conversione eol", con l' imminente Git 1.7.2 :

È core.eolstata aggiunta / evoluta una nuova impostazione di configurazione :

Questo è un sostituto del core.eolcommit "Aggiungi" "variabile di configurazione" attualmente in uso pu(l'ultimo della mia serie).
Invece di implicare che " core.autocrlf=true" è un sostituto di " * text=auto", rende esplicito il fatto che autocrlfè solo per gli utenti che vogliono lavorare con i CRLF nella loro directory di lavoro su un repository che non ha la normalizzazione dei file di testo .
Quando è abilitato, "core.eol" viene ignorato.

Introdurre una nuova variabile di configurazione, " core.eol", che consente all'utente di impostare quali terminazioni di riga utilizzare per i file normalizzati di fine riga nella directory di lavoro.
L'impostazione predefinita è " native", che significa CRLF su Windows e LF ovunque. Si noti che " core.autocrlf" sostituisce core.eol.
Ciò significa che:

[core]
  autocrlf = true

mette i CRLF nella directory di lavoro anche se core.eolè impostato su " lf".

core.eol:

Imposta il tipo di fine riga da utilizzare nella directory di lavoro per i file con la textproprietà impostata.
Le alternative sono 'lf', 'crlf' e 'native', che utilizza il finale di linea nativo della piattaforma.
Il valore predefinito è native.


Altre evoluzioni sono state prese in considerazione :

Per 1.8, vorrei prendere in considerazione facendo core.autocrlfbasta accendere la normalizzazione e lasciare la linea di directory di lavoro che termina decisione di core.eol, ma che vi romperà messe a punto delle persone.


git 2.8 (marzo 2016) migliora il modo in cui core.autocrlfinfluenza l'eol:

Vedere commit 817a0c7 (23 feb 2016), commit 6e336a5 , commit df747b8 , commit df747b8 (10 feb 2016), commit df747b8 , commit df747b8 (10 feb 2016), e impegnarsi 4b4024f , commit bb211b4 , commit 92cce13 , commit 320d39c , commit 4b4024f , commit bb211b4 , commit 92cce13 , commit 320d39c (05 feb 2016) di Torsten Bögershausen ( tboegi) .
(Unito da Junio ​​C Hamano - gitster- in commit c6b94eb, 26 feb 2016)

convert.c: refactor crlf_action

Rifattorizzare la determinazione e l'utilizzo di crlf_action.
Oggi, quando nessun " crlf" attributo è impostato su un file, crlf_actionè impostato su CRLF_GUESS. Usa CRLF_UNDEFINEDinvece e cerca " text" o " eol" come prima.

Sostituisci il vecchio CRLF_GUESSutilizzo:

CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT

Rendi più chiaro, che cos'è, definendo:

- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
                   and core.eol is evaluated and one of CRLF_BINARY,
                   CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY    : No processing of line endings.
- CRLF_TEXT      : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO      : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true  (no attributes)

Come aggiunge Torek nei commenti :

tutte queste traduzioni (qualsiasi conversione da EOL eol=o autocrlfimpostazioni e cleanfiltri " ") vengono eseguite quando i file si spostano dall'albero di lavoro all'indice , ovvero durante git addanziché al git commitmomento.
(Si noti che git commit -ao --onlyo --includeaggiungere file all'indice in quel momento, però.)

Per ulteriori informazioni, vedere " Qual è la differenza tra autocrlf ed eol ".


18
Questo, sfortunatamente, non aggiunge chiarezza per me. Sembra che stiano dicendo che ci sono problemi con l'attuale implementazione (non è chiaro quali siano questi problemi) e stanno aumentando la complessità nel tentativo di risolvere quei problemi non specificati. A mio avviso, l'impostazione core.autocrlf è già eccessivamente complessa e sotto documentata e la situazione sembra peggiorare. Grazie ancora per l'heads up.
Michael Maddox,

1
Questa non sembra una soluzione soddisfacente e sembra avere gli stessi problemi di core.autocrlf. La mia preferenza sarebbe se git non modificasse mai automaticamente nulla, ma avvertirebbe l'utente che desidera aggiungere o commettere i finali di riga errati. Quindi avresti bisogno di un'opzione da riga di comando per consentire a "git add" di aggiungere le terminazioni di riga "errate". (probabilmente git add è il posto migliore per verificarlo rispetto a git commit)
donquixote,

Ciò costringerebbe il rispettivo utente a modificare le impostazioni dell'editor e ad occuparsi davvero del problema. Mentre consentirebbe di lasciare le terminazioni di riga "errate" per i file di terze parti o che sono già stati registrati nel repository.
donquixote,

@donquixote di nuovo, sono d'accordo. Ma si core.eoltratta di "modificare automaticamente" solo ciò che si dichiara esplicitamente in un .gitattributesfile. Questo è diverso da quello core.autocrlfche si applica a qualsiasi file nel repository. È un processo dichiarativo.
VonC,

1
@donquixote: mi rendo conto che è piuttosto vecchio, ma ho letto solo il tuo commento ora. In effetti, tutte queste traduzioni (qualsiasi conversione EOL dalle impostazioni eol = o autocrlf e filtri "puliti") vengono eseguite quando i file si spostano dall'albero di lavoro all'indice, ovvero durante git addanziché al git commitmomento. (Nota che git commit -ao --onlyo --includeaggiungi file all'indice in quel momento, però.) Per quello che vale, io e Linus Torvald odiamo tutti l'idea di un VCS che modifichi mai ciò che è stato commesso. Ma ci sono tutti quegli utenti Windows ... :-)
torek

34

core.autocrlfil valore non dipende dal tipo di sistema operativo ma dal valore predefinito di Windows è truee per Linux - input. Ho esplorato 3 possibili valori per i casi di commit e checkout e questa è la tabella risultante:

╔═══════════════╦══════════════╦══════════════╦══════════════╗
║ core.autocrlf ║     false    ║     input    ║     true     ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => LF   ║
║ git commit    ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => LF   ║ CRLF => LF   ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => CRLF ║
║ git checkout  ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║
╚═══════════════╩══════════════╩══════════════╩══════════════╝

5
Breve riassunto in parole: i file con CRsoli non vengono mai toccati. falsenon tocca mai le terminazioni di linea. truesi impegna sempre come LFe verifica come CRLF. E inputsi impegna sempre come LFe verifica così com'è.
Furkan Kambay,

7

Ecco la mia comprensione finora, nel caso in cui aiuti qualcuno.

core.autocrlf=true e core.safecrlf = true

Hai un repository in cui tutte le terminazioni di linea sono uguali , ma lavori su piattaforme diverse. Git si assicurerà che le terminazioni delle linee vengano convertite nel valore predefinito per la tua piattaforma. Perché è importante? Diciamo che crei un nuovo file. L'editor di testo sulla tua piattaforma utilizzerà i finali di riga predefiniti. Quando esegui il check-in, se core.autocrlf non è impostato su true, hai introdotto un'incoerenza di fine riga per qualcuno su una piattaforma che imposta automaticamente un finale di linea diverso. Ho sempre impostato anche safecrlf perché vorrei sapere che l'operazione crlf è reversibile. Con queste due impostazioni, git sta modificando i tuoi file, ma verifica che le modifiche siano reversibili .

core.autocrlf=false

Si dispone di un repository che ha già archiviato le terminazioni di riga miste e la correzione delle terminazioni di riga errate potrebbe interrompere altre cose. In questo caso è meglio non dire a git di convertire le terminazioni di linea, perché in questo modo si aggraverà il problema che è stato progettato per risolvere, rendendo le differenze più facili da leggere e le fusioni meno dolorose. Con questa impostazione, git non modifica i tuoi file .

core.autocrlf=input

Non lo uso perché il motivo di ciò è quello di coprire un caso d'uso in cui è stato creato un file con terminazioni di linea CRLF su una piattaforma per impostazione predefinita alle terminazioni di linea LF. Preferisco invece fare in modo che il mio editor di testo salvi sempre nuovi file con i valori predefiniti della riga della piattaforma.


3

No, la risposta @jmlane è errata.

Per Checkin (git add, git commit):

  1. se la textproprietà èSet, Set value to 'auto' , la conversione avviene quando il file è stato eseguito il commit con 'CRLF'
  2. se la textproprietà è Unset: non succede nulla, enen forCheckout
  3. se la textproprietà è Unspecified, la conversione dipendecore.autocrlf
    1. Se autocrlf = input or autocrlf = true la conversione avviene solo quando il file nel repository è 'LF', se è stato 'CRLF', non accadrà nulla.
    2. se autocrlf = falsenon succede nulla

Per Checkout:

  1. se la textproprietà èUnset : non succede nulla.
  2. se la textproprietà è Set, Set value to 'auto: dipende da core.autocrlf,core.eol .
    1. core.autocrlf = input: non succede nulla
    2. core.autocrlf = true: la conversione avviene solo quando il file nel repository è 'LF', 'LF' -> 'CRLF'
    3. core.autocrlf = false: la conversione avviene solo quando il file nel repository è 'LF', 'LF' -> core.eol
  3. se la textproprietà è Unspecified, dipende da core.autocrlf.
    1. lo stesso di 2.1
    2. lo stesso di 2.2
    3. Nessuno, non succede nulla, core.eol non è efficace quando lo textè la proprietàUnspecified

Comportamento predefinito

Quindi il comportamento predefinito è la textproprietà è Unspecifiede core.autocrlf = false:

  1. per il check-in, non succede nulla
  2. per il checkout, non succede nulla

conclusioni

  1. se la textproprietà è impostata, il comportamento del check-in dipende da se stesso, non da autocrlf
  2. autocrlf o core.eol è per il comportamento di checkout e autocrlf> core.eol

2

Ho fatto alcuni test sia su Linux che su Windows. Uso un file di test contenente le righe che terminano in LF e anche le righe che terminano in CRLF.
Il file viene eseguito il commit, rimosso e quindi estratto. Il valore di core.autocrlf è impostato prima del commit e anche prima del checkout. Il risultato è sotto.

commit core.autocrlf false, remove, checkout core.autocrlf false: LF=>LF   CRLF=>CRLF  
commit core.autocrlf false, remove, checkout core.autocrlf input: LF=>LF   CRLF=>CRLF  
commit core.autocrlf false, remove, checkout core.autocrlf true : LF=>LF   CRLF=>CRLF  
commit core.autocrlf input, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF  
commit core.autocrlf input, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF  
commit core.autocrlf input, remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF  
commit core.autocrlf true, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF  
commit core.autocrlf true, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF  
commit core.autocrlf true,  remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF  
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.