2010-10-15 10 views
56

Mentre in qualche modo esperto in VCS (regolare svn, git e git-svn utente) non riesco a capirmi di questo strano comportamento SVN.Un modo corretto per rinominare una directory in copia di lavoro di subversion

Ogni volta che ho bisogno di rinominare una cartella nella mia copia di lavoro SVN da uno stato altrimenti 'pulito' - vale a dire svn status restituisce nulla e sono stati commesso tutte le altre modifiche - in questo modo (che è ciò che suggerisce il doc svn):

svn mv foo bar 
svn commit 

SVN si lamenta ad alta voce:

Adding   bar 
Adding   bar/toto 
Deleting  foo 
svn: Commit failed (details follow): 
svn: Item '/test/foo' is out of date 

Come desideri:

svn update 

che dà:

C foo 
At revision 46. 
Summary of conflicts: 
    Tree conflicts: 1 

C'è un conflitto albero, mentre nessun cambiamento di terze parti è accaduto. Ovviamente, l'unico modo per uscire da questo pasticcio albero conflitto è generico (dal libro rosso svn):

svn resolve --accept working -R . 
svn commit 

Rinominare in remoto sul repo quindi aggiornare la mia copia di lavoro sembra abbastanza braindead:

url=$(svn info | grep -e '^URL:' | sed 's/^URL: //') svn mv $url/foo $url/bar 
svn update 

Esiste un modo sanzionato e semplificato per rinominare una cartella che mi manca? Qual è la causa alla base di questo stato di conflitto dell'albero particolarmente sorprendente?

+0

Puoi pubblicare il messaggio esatto di conflitto dell'albero? –

+0

Ho visto questo comportamento anche prima, ma non sono sicuro di quale sia la causa. È quando si aggiunge una dir e la si rinomina prima di impegnarsi forse? –

+0

Ho riscontrato questo comportamento e non sono stato in grado di capire un motivo. L'ho sempre attribuito a "come funziona SVN". Mi fa impazzire. –

risposta

56

svn mv funziona per me:

C:\svn\co>svn mv my_dir new_dir 
A   new_dir 
D   my_dir\New Text Document.txt 
D   my_dir 


C:\svn\co>svn commit -m foo 
Raderar    my_dir 
Lägger till   new_dir 

Arkiverade revision 2. 

C:\svn\co> 

Ci scusiamo per l'uscita svedese del svn.

Ci deve essere qualcos'altro che non va nel tuo caso.

Edit:
Come sottolineato nei commenti da Lloeki

Per riprodurre il problema è necessario anche aggiornare e commettere un file contenuto nella cartella, ma non aggiorna la cartella stessa.

file di commettere crea una nuova rev n sul pronti contro termine, ma i metadati locale non viene aggiornato (come ha sempre, vedi svn registro dopo ogni commit), quindi dir metadati è a giri N- 1. Segue che svn non eseguirà il commit a causa del diff di metadati e non aggiornerà perché in effetti esiste un conflitto su la directory: aggiornamento metadati vs delete.

Il comportamento è "previsto" e la "soluzione" è di aggiornare la copia di lavoro prima di emettere il comando svn rename.

+2

Scoprire che "qualcos'altro" è in realtà parte della domanda :) Ora modifica New Text Document.txt, esegui il commit, quindi mv the dir e commit di nuovo. – Lloeki

+1

@Lloeki, sì modificando il file di testo riproduce il conflitto dell'albero. Sembra davvero un bug per me, hai cercato il tracker dei problemi su http://subversion.apache.org/ e/o hai presentato una segnalazione di bug? –

+2

Alla fine ho trovato il motivo, che ha senso in modo sovvertito: il file commit crea un nuovo rev * n * sul repository, ma i metadati locali non vengono aggiornati (come è sempre stato, vedi 'svn log' dopo ogni commit) , quindi i metadati della directory è a rev * n-1 *. Ne consegue che svn non eseguirà il commit a causa del diff di metadati e non si aggiornerà perché in effetti esiste un conflitto nella directory: update metadata vs delete. – Lloeki

0

Si potrebbe pensare a uno scenario in cui la directory è stata modificata nel repository da un altro utente. Rinominare la stessa cartella nella tua copia di lavoro può innescare conflitti tra alberi durante il commit.

Resolving conflicts mostra come risolvere "conflitti ad albero" in sovversione.

+0

Sono in uno scenario di sviluppo solitario in cui non si verificano cambiamenti esterni. – Lloeki

1

questo ha funzionato per me:

vi someotherfile 
...various changes to the other file 
svn mv olddir newdir 
svn commit -m"Moved olddir out of the way" olddir 
svn commit -m"New location of olddir" newdir 
svn update 
svn commit -m"Changed someotherfile" someotherfile 

ho il sospetto che ci sono stati vari altri modi possibili rotonda, e che assicurare c'era una directory di lavoro pulita prima di fare il mv svn avrebbe anche fatto il trucco.

7

OK, mi sono imbattuto in questo - e posso finalmente ricostruire il problema con una semplice sessione di terminale: il problema si verifica se si sposta un file svn mv (sposta/rinomina); poi commetti quel cambiamento; poi (senza facendo un svn update prima), svn mv la directory principale del file il cui spostamento/rinomina era precedentemente impegnata - e, infine, fare un svn commit sul cambiamento del nome della directory - o come accepted answer lo mette: "è inoltre necessario per aggiornare e salvare un file contenuto nella cartella, ma non aggiornare la cartella stessa "; ma tutto ciò eseguito in una directory genitore (o piuttosto, antenato). Ecco il comando di registro linea che dimostra il problema:

$ cd /tmp 
$ svnadmin create myrepo 
$ svn co file:///tmp/myrepo myrepo-wc 
Checked out revision 0. 

$ cd myrepo-wc/ 
$ mkdir -p dir1/dir2/dir3 
$ svn add dir1/ 
A   dir1 
A   dir1/dir2 
A   dir1/dir2/dir3 

$ svn ci -m 'add dir1/' 
Adding   dir1 
Adding   dir1/dir2 
Adding   dir1/dir2/dir3 

Committed revision 1. 

$ echo test1 >> dir1/dir2/dir3/test1.txt 
$ echo test2 >> dir1/dir2/dir3/test2.txt 
$ svn add dir1/ 
svn: warning: 'dir1' is already under version control 
$ svn add dir1/* 
svn: warning: 'dir1/dir2' is already under version control 
$ svn add dir1/dir2/dir3/* 
A   dir1/dir2/dir3/test1.txt 
A   dir1/dir2/dir3/test2.txt 
$ svn status 
A  dir1/dir2/dir3/test2.txt 
A  dir1/dir2/dir3/test1.txt 
$ svn ci -m 'add dir1/dir2/dir3/*' 
Adding   dir1/dir2/dir3/test1.txt 
Adding   dir1/dir2/dir3/test2.txt 
Transmitting file data .. 
Committed revision 2. 

$ svn mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt 
A   dir1/dir2/dir3/test2X.txt 
D   dir1/dir2/dir3/test2.txt 
$ svn status 
D  dir1/dir2/dir3/test2.txt 
A + dir1/dir2/dir3/test2X.txt 
$ svn ci -m 'mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt' 
Deleting  dir1/dir2/dir3/test2.txt 
Adding   dir1/dir2/dir3/test2X.txt 

Committed revision 3. 

$ svn status 
$ svn mv dir1/dir2/dir3 dir1/dir2/dir3X 
A   dir1/dir2/dir3X 
D   dir1/dir2/dir3/test2X.txt 
D   dir1/dir2/dir3/test1.txt 
D   dir1/dir2/dir3 
$ svn status 
D  dir1/dir2/dir3 
D  dir1/dir2/dir3/test2X.txt 
D  dir1/dir2/dir3/test1.txt 
A + dir1/dir2/dir3X 
D + dir1/dir2/dir3X/test2.txt 
$ svn ci -m 'mv dir1/dir2/dir3 dir1/dir2/dir3X' 
Deleting  dir1/dir2/dir3 
svn: Commit failed (details follow): 
svn: Directory '/dir1/dir2/dir3' is out of date 
$ svn status 
D  dir1/dir2/dir3 
D  dir1/dir2/dir3/test2X.txt 
D  dir1/dir2/dir3/test1.txt 
A + dir1/dir2/dir3X 
D + dir1/dir2/dir3X/test2.txt 
$ svn up 
    C dir1/dir2/dir3 
At revision 3. 
Summary of conflicts: 
    Tree conflicts: 1 

E questo è come avrebbe dovuto essere - facendo un svn up dopo che il file spostare/rinominare stato ha commesso; notare come i numeri di versione riportati da svn status -v cambiamento dopo il comando svn update:

$ cd /tmp 
$ rm -rf myrepo* 

$ svnadmin create myrepo 
$ svn co file:///tmp/myrepo myrepo-wc 
Checked out revision 0. 

$ cd myrepo-wc/ 
$ mkdir -p dir1/dir2/dir3 
$ svn add dir1/ 
A   dir1 
A   dir1/dir2 
A   dir1/dir2/dir3 
$ svn ci -m 'add dir1/' 
Adding   dir1 
Adding   dir1/dir2 
Adding   dir1/dir2/dir3 

Committed revision 1. 

$ echo test1 >> dir1/dir2/dir3/test1.txt 
$ echo test2 >> dir1/dir2/dir3/test2.txt 
$ svn add dir1/dir2/dir3/* 
A   dir1/dir2/dir3/test1.txt 
A   dir1/dir2/dir3/test2.txt 
$ svn status 
A  dir1/dir2/dir3/test2.txt 
A  dir1/dir2/dir3/test1.txt 
$ svn ci -m 'add dir1/dir2/dir3/*' 
Adding   dir1/dir2/dir3/test1.txt 
Adding   dir1/dir2/dir3/test2.txt 
Transmitting file data .. 
Committed revision 2. 

$ svn mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt 
A   dir1/dir2/dir3/test2X.txt 
D   dir1/dir2/dir3/test2.txt 
$ svn status 
D  dir1/dir2/dir3/test2.txt 
A + dir1/dir2/dir3/test2X.txt 
$ svn ci -m 'mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt' 
Deleting  dir1/dir2/dir3/test2.txt 
Adding   dir1/dir2/dir3/test2X.txt 

Committed revision 3. 

$ svn status 
$ svn status -v 
       0  0 ?   . 
       1  1 username dir1 
       1  1 username dir1/dir2 
       1  1 username dir1/dir2/dir3 
       3  3 username dir1/dir2/dir3/test2X.txt 
       2  2 username dir1/dir2/dir3/test1.txt 
$ svn up 
At revision 3. 
$ svn status -v 
       3  3 username . 
       3  3 username dir1 
       3  3 username dir1/dir2 
       3  3 username dir1/dir2/dir3 
       3  3 username dir1/dir2/dir3/test2X.txt 
       3  2 username dir1/dir2/dir3/test1.txt 
$ svn mv dir1/dir2/dir3 dir1/dir2/dir3X 
A   dir1/dir2/dir3X 
D   dir1/dir2/dir3/test2X.txt 
D   dir1/dir2/dir3/test1.txt 
D   dir1/dir2/dir3 
$ svn status 
D  dir1/dir2/dir3 
D  dir1/dir2/dir3/test2X.txt 
D  dir1/dir2/dir3/test1.txt 
A + dir1/dir2/dir3X 
$ svn ci -m 'mv dir1/dir2/dir3 dir1/dir2/dir3X' 
Deleting  dir1/dir2/dir3 
Adding   dir1/dir2/dir3X 

Committed revision 4. 

$ svn status 
$ svn status -v 
       3  3 username . 
       3  3 username dir1 
       3  3 username dir1/dir2 
       4  4 username dir1/dir2/dir3X 
       4  4 username dir1/dir2/dir3X/test2X.txt 
       4  4 username dir1/dir2/dir3X/test1.txt 
$ svn up 
At revision 4. 
$ svn status -v 
       4  4 username . 
       4  4 username dir1 
       4  4 username dir1/dir2 
       4  4 username dir1/dir2/dir3X 
       4  4 username dir1/dir2/dir3X/test2X.txt 
       4  4 username dir1/dir2/dir3X/test1.txt 

E come ha detto OP - si dovrebbe dimenticare di fare il svn update prima di una nuova mossa/rinominare + commit, e il "commit fallito" si è verificato - quindi si può usare svn resolve --accept working -R . per poter completare l'azione di commit.

Problemi correlati