2012-06-25 11 views
8

Nell'esplorare funzionalità in Subversion, ho cercato di testare il caso d'uso descritte nel Annullamento Modifiche sottosezione della sezione di base fusione delle ramificazione e la fusione capitolo del svnbook. Sto usando la versione 1.6.4, ma il testo per quella sezione è lo stesso in entrambe le versioni del libro.conflitto quando si tenta Annullare le modifiche esempio in Subversion

Nella mia directory di copia di lavoro, modifico un file testcode.py, aggiungendo una riga per modifica e confermando dopo ogni modifica. Dopo diversi commit, il file si legge come segue:

this is my first import to trunk. r1. 

this is my first commit, first edit of testcode.py. r2. 

this is another edit of testcode.py. r3. 

this is an edit of testcode.py. i'll get rid of this one. r4. 

this is another edit of testcode.py. keeping it. r5. 

yet another edit. keeping it. r6. 

I numeri di revisione nella partita repository fino alle righe nel file in modo tale che nel /trunk/[email protected], l'ultima riga del file è quello che termina con rN. Quello che voglio fare è rimuovere la riga che termina in r4, mantenendo tutto il resto prima e dopo invariato.

Seguendo l'esempio nella sezione Annullare le modifiche del svnbook, faccio funzionare l'ordine

svn merge -c -4 file:///path_to_repos/trunk 

Questo crea un conflitto (su corsa che comando, non il commit), per cui il file di unione a sinistra contiene tutto fino alla riga r4 e il file merge-right contiene tutto fino alla riga r3. In altre parole, invece di rimuovere una modifica passata, sembra che il comando voglia ripristinare l'intero file alla versione 3 o 4, rimuovendo le modifiche nelle revisioni successive (5 e 6, in questo caso).

Il modo in cui leggo l'esempio nel svnbook, che ha l'utente che inverte una modifica impegnata nella revisione 303 e che commette il risultato in revisione 350 senza conflitti, il comando che ho eseguito dovrebbe aver prodotto un file con uno stato svn di M che conserva tutte le righe tranne quella che termina in r4.

Sto leggendo l'esempio del libro in modo errato, l'esempio è sbagliato, oppure c'è qualche altra forma di errore utente in cui sono caduto inconsapevolmente?

+0

Decisamente riproducibile. Ora devi pensare perché succede. –

+0

Creare una patch con 'svn diff -c -4 foo.txt> foo.patch' e quindi applicarla a' foo.txt @ HEAD' funziona come previsto - rimuove la riga r4. –

+1

Quindi le patch funzionano, ma "un caso d'uso estremamente comune per ** svn merge **," come dice il libro svn, un semplice che ha la sua sottosezione, semplicemente no. Ciò non ispira fiducia nel comportamento della funzione di fusione di Subversion in procedure più complesse, come il reinserimento di rami. – krosbonz

risposta

4

Il problema di base è che l'algoritmo diff di Subversion gestisce le modifiche all'inizio e alla fine dei file in un modo non necessariamente intuitivo. Il tuo esempio colpisce il caso in questione, mentre la maggior parte dei cambiamenti in natura non lo fanno. Consideriamo un file che assomiglia a questa dopo una serie di commit:

later commit (r5) 
change to be reverted at beginning of file (r2) 
initial commit (r1) 
change to be reverted in middle of file (r3) 
initial commit (r1) 
change to be reverted at end of file (r4) 
later commit (r5) 

Cercando di ripristinare le commit all'inizio o alla fine del file (revisioni 2 e 4 nell'esempio), dà un conflitto. Il ripristino della modifica al centro del file funziona come previsto.

Concettualmente, potrebbe essere utile pensare che i changeset abbiano un ambito limitato dalle linee circostanti. Una modifica al centro di un file è limitata dalle linee immutate circostanti. L'ambito di una modifica all'inizio o alla fine di un file si estende fino all'inizio o alla fine del file indipendentemente da quanto lontano tale punto viene successivamente spostato.

Quindi nell'esempio sopra, la seconda riga aggiunta nella revisione 5 arriva proprio nel mezzo dell'ambito della revisione 4.Nello stesso modo in cui ci si aspetta un conflitto di ritornare revisione 10 qui perché cambiamenti nella revisione 11 sono nel bel mezzo di esso:

...     <-- Line unchanged by revision 10, bounding its scope 
line from revision 10 <--\ 
line from revision 11  | Revision 10's scope 
line from revision 10 <--/ 
...     <-- Line unchanged by revision 10, bounding its scope 

si dovrebbe aspettare un conflitto qui, per lo stesso motivo:

...     <-- Line unchanged by revision 10, bounding its scope 
line from revision 10 <--\ 
line from revision 11  | Revision 10's scope 
<EOF>     <--/ (No unchanged line bounding the scope this direction) 

Si noti che questo è inteso solo come una spiegazione concettuale del motivo per cui l'inizio e la fine del file sono apparentemente trattati in modo diverso, non come una spiegazione completa per la comprensione del processo di unione di Subversion.

+0

Molto interessante e riproducibile al 100%. Grazie! Hai trovato questo sperimentando, hai scritto l'algoritmo diff, o è documentato da qualche parte? Potrei pensare di mettere una riga "fittizia" nei miei file all'inizio e - specialmente - alla fine ora. – scherand

+0

Questo è solo per esperienza. In realtà ho cercato con cura la documentazione da includere in questa risposta, ma non ho trovato nulla. – blahdiblah

+0

Giusto per essere sicuro di comprendere appieno, posso dire quanto segue? La prima (più vicina all'inizio) e l'ultima (più vicina alla fine) di un gruppo di modifiche definiscono il suo "ambito". Se la prima riga della modifica è la prima riga del file (o l'ultima l'ultima) l'ambito si estenderà in alto/in basso per sempre. E: se qualcosa è cambiato * nell'ambito * di quel cambiamento impostato in un commit successivo, il set di modifiche originale non può essere invertito senza creare un conflitto. Vero o falso? :) – scherand

Problemi correlati