J'utilise git-svn et j'ai remarqué que lorsque je dois résoudre un conflit de fusion après avoir effectué un git svn rebase
, la signification du --ours
et --theirs
options pour par exemple git checkout
est inversé. Autrement dit, s'il y a un conflit et que je souhaite conserver la version provenant du serveur SVN et supprimer les modifications que j'ai apportées localement, je dois utiliser ours
, quand je m'attends à ce que ce soit theirs
.
Pourquoi donc?
Exemple:
mkdir test
cd test
svnadmin create svnrepo
svn co file://$PWD/svnrepo svnwc
cd svnwc
echo foo > test.txt
svn add test.txt
svn ci -m 'svn commit 1'
cd ..
git svn clone file://$PWD/svnrepo gitwc
cd svnwc
echo bar > test.txt
svn ci -m 'svn commit 2'
cd ..
cd gitwc
echo baz > test.txt
git commit -a -m 'git commit 1'
git svn rebase
git checkout --ours test.txt
cat test.txt
# shows "bar" but I expect "baz"
git checkout --theirs test.txt
cat test.txt
# shows "baz" but I expect "bar"
Cela semble cohérent avec ce que fait un rebase.
git svn rebase
récupérera les révisions du parent SVN du courant HEAD et rebasera le travail courant (non engagé sur SVN) par rapport à lui.
git rebase
mentionne:
Notez qu'une fusion de rebase fonctionne en relisant chaque commit à partir de la branche de travail en haut de <upstream>
branche.
Pour cette raison, lorsqu'un conflit de fusion se produit:
<upstream>
,git rebase rejoue chaque commit à partir de la branche de travail en haut de
<upstream>
branche.
Si vous conciliez les deux définitions:
test.txt
fichier avec bar
contenu)test.txt
fichier avec baz
contenu) est "leur", et chacun de ces commits Git locaux est en cours de relecture.En d'autres termes, SVN ou non:
<upstream>
"la branche (au dessus de laquelle tout est rejoué, et qui fait partie des commits rebasés jusqu'à présent") est " la nôtre ".Bon astuce mnémonique par CommaToast :
tout ce que HEAD pointe est "le nôtre"
(et la première chose qu'un git rebase upstream
le fait pour extraire la branche upstream
au dessus de laquelle vous souhaitez rebaser: HEAD fait référence à upstream
- ours
now .)
La confusion vient probablement du rôle de la branche de travail dans un classique git merge
.
Lorsque vous fusionnez:
Comme le git rebase
page de manuel mentionne, une fusion lors d'un rebase signifie que le côté est échangé.
Une autre façon de dire la même chose est de considérer que:
Lors d'une fusion :
x--x--x--x--x(*) <- current branch B ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
, nous ne changeons pas la branche actuelle 'B', donc ce que nous avons est toujours ce sur quoi nous travaillions (et nous fusionnons à partir d'une autre branche)
x--x--x--x--x---------o(*) MERGE, still on branch B
\ ^ /
\ ours /
\ /
--y--y--y--/
^
their
Mais sur un rebase , nous changeons de côté car la première chose qu'un rebase fait est de vérifier la branche en amont! (pour rejouer les validations actuelles par-dessus)
x--x--x--x--x(*) <- current branch B
\
\
\--y--y--y <- upstream branch
A git rebase upstream
changera d'abord HEAD
de B en la branche amont HEAD
(d'où le basculement de 'nôtre' et 'leur' par rapport au précédent "courant") "branche de travail.)
x--x--x--x--x <- former "current" branch, new "theirs"
\
\
\--y--y--y(*) <- upstream branch with B reset on it,
new "ours", to replay x's on it
, puis le rebase rejouera "leurs" commits sur la nouvelle "notre" branche B:
x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
\
\
\--y--y--y--x'--x'--x'(*) <- branch B with HEAD updated ("ours")
^
|
upstream branch
La seule étape supplémentaire avec git svn rebase
est qu'une "récupération" svn est effectuée en premier sur la branche distante Git représentant les validations SVN.
Vous avez initialement:
x--x--x--x--x(*) <- current branch B, "ours" for now.
\
\
\--y--y--y <- SVN tracking branch, "theirs for now"
, vous mettez d'abord à jour la branche de suivi SVN avec de nouveaux commits venant de SVN
x--x--x--x--x(*) <- current branch B, still "ours", not for long
\
\
\--y--y--y--y'--y' <- SVN tracking branch updated
, puis vous basculez la branche actuelle du côté SVN (qui devient "la nôtre")
x--x--x--x--x <- for "B", now "their" during the rebase
\
\
\--y--y--y--y'--y'(*) <- SVN tracking branch updated, and branch B:
now "ours" (this is "what we now have")
, avant de rejouer les commits sur lesquels vous travailliez (mais qui sont désormais "les leurs" lors de ce rebase)
x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
\
\
\--y--y--y--y'--y'--x'--x'--x'(*) <- branch B with HEAD updated ("ours")
^
|
upstream SVN tracking branch