Perché git non unisce le linee adiacenti senza conflitto?

17

Recentemente ho imparato che quando si uniscono due rami in git, se ci sono cambiamenti su due righe adiacenti , git dichiara questo un conflitto. Ad esempio, se il file test.txt ha questo contenuto:

Line 1: A
Line 2: B
Line 3: C
Line 4: D

e nel ramo master lo cambiamo in

Line 1: A
Line 2: B1
Line 3: C
Line 4: D

mentre nel ramo testing lo cambiamo in

Line 1: A
Line 2: B
Line 3: C1
Line 4: D

e quindi tenta di unire testing in master , git dichiara un conflitto di unione. La mia ingenua aspettativa era che l'unione sarebbe avvenuta senza conflitto e avrebbe prodotto questo:

Line 1: A
Line 2: B1
Line 3: C1
Line 4: D

Sono sicuro che esiste una buona ragione per cui git non si fonde in questo modo. Qualcuno può spiegare questo motivo?

    
posta rlandster 13.04.2013 - 00:20
fonte

4 risposte

12

Supponendo che questo snippet di codice

x=0
x+=1 if foo
x+=1 if bar
return x

è stato modificato in un ramo in questo

x=0
x+=1 if foo && xyzzy
x+=1 if bar
return x

e in un altro ramo in questo

x=0
x+=1 if foo
x+=1 if bar && xyzzy
return x

quindi non vorrei che git lo unisse in questo

x=0
x+=1 if foo && xyzzy
x+=1 if bar && xyzzy
return x

senza allarmarmi.

Questo esempio è banale, ma quando si uniscono rami enormi il rischio di conflitti "logici" simili è molto più grande. A volte vorrei persino che il contesto sia ancora più grande di quello che è attualmente.

    
risposta data 21.04.2015 - 16:04
fonte
10

Questo comportamento git-only?

Dopo aver discusso con un collega, ho appena provato e SVN lo gestisce senza problemi: ottieni le 2 linee modificate.

Le funzionalità di fusione di diversi VCS sono testate qui per bazaar, darcs, git e mercurial : link

Sembra che solo gli darcs uniscano il caso "linee adiacenti".

L'applicazione di modifiche adiacenti ai file non è un problema difficile. Penso davvero che questo comportamento sia stato scelto appositamente.

Perché qualcuno dovrebbe decidere che la modifica delle righe adiacenti produce un conflitto?

Penso che questo sia per costringerti a guardarlo .

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif numero 1, su master:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif numero 2, unito da un ramo:

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

Dopo l'unione, non vuoi che:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

Visualizzazione di questo comportamento come funzione

È possibile trasformare il comportamento di fusione git in un vantaggio. Quando devi mantenere 2 linee coerenti ma non riesci a rilevarle (al momento della compilazione, all'inizio dei test o altro), puoi provare a unirti a loro.

Riscrivi questo ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    // Need to do something else
    do_something_else(r);

... a questo:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    do_something_else(r); // Need to do something else

Quindi quando unisci Modif 1 ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i)/2; // we need only the half
    do_something_else(r); // Need to do something else

... con Modif 2 ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    if(r < 0) // do_stuff can return an error
        handle_error(r);
    do_something_else(r/2); // Need to do something else

..., git produrrà un conflitto e ti costringerà a guardarlo.

    
risposta data 04.03.2016 - 14:34
fonte
5

Per lo più indovino, ma penso che abbia a che fare con la linea 2 usata come contesto per il cambio di riga 3.

Git non può semplicemente dire che "La linea con C è diventata una linea con C1" perché potrebbe esserci un'altra linea con "C", quindi dice "La linea con C, giusto dopo l'inizio del file, la linea con A e la linea con B, ora è C1 "

Se "la linea con B" non è più lì, allora parte del contesto è persa, e git può solo dire approssimativamente dove deve andare la nuova linea.

    
risposta data 13.04.2013 - 00:38
fonte
-1

Le altre risposte qui sono tutte azzeccate, ma per me questo mi è sempre sembrato un limite inutile.

Come altri hanno già detto, in questi casi non vorrai assolutamente che Git unisca le linee senza preavviso.

Ma volevo ancora l'opzione di farlo automaticamente, dopo essere stato avvisato. Così ho scritto un driver git merge personalizzato che poteva unire i conflitti sulle linee adiacenti (o individuali) in modo interattivo:

Mifarisparmiareunsaccoditempo,perchégestiscounprogettoincuilepersonelavoranospessosuglistessifileerefactoringunsaccodicodice.

LoscriptèdisponibilesuGitHubconunalicenzaGPLv3+.Forselotroveraiutile:

link

    
risposta data 11.09.2018 - 03:20
fonte

Leggi altre domande sui tag