From: Josef Wolf <jw@raven.inka.de>
To: Avery Pennarun <apenwarr@gmail.com>
Cc: git@vger.kernel.org
Subject: Re: Trying to sync two svn repositories with git-svn (repost)
Date: Fri, 1 May 2009 00:28:09 +0200 [thread overview]
Message-ID: <20090430222808.GH15420@raven.wolf.lan> (raw)
In-Reply-To: <32541b130904291907q4003ad86v4728c5b2ba0aacb7@mail.gmail.com>
On Wed, Apr 29, 2009 at 10:07:31PM -0400, Avery Pennarun wrote:
> On Wed, Apr 29, 2009 at 6:37 PM, Josef Wolf <jw@raven.inka.de> wrote:
> > On Wed, Apr 29, 2009 at 02:13:29PM -0400, Avery Pennarun wrote:
> >> So you're saying that from now on, *all* changes from *both* branches
> >> need to be integrated in both directions?
> >
> > Exactly. Those three commands:
> >
> > git diff first-svn second-svn # this should be the "private" diff
> > git diff first-svn/trunk first-svn # what my cherry-picking has changed
> > # (and waits for push) in first-svn
> > git diff second-svn/trunk second-svn # what my cherry-picking has changed
> > # (and waits for push) in second-svn
> >
> > show me _exactly_ what I want them to be. The manual synchronizations
> > which were done in the past are resolved now. But I can't find the way
> > how to put the result of this cherry-picking back into the svn repositories
>
> Okay, I think perhaps you're missing something that took me a long
> time to figure out about git-svn, but once I understood it, my life
> went a lot more smoothly.
>
> Basically, 'git svn fetch' updates just a *remote* branch. (Remote
> branches are in .git/refs/remotes/* and you can't change them
> yourself, because you can't attach your HEAD to them. If you try to
> check them out, you get the latest revision in that branch, but your
> HEAD becomes detached.)
>
> I'm not actually sure which of the above branches you're referring to
> is remote and which is local. Let's guess that first-svn/trunk is
> remote, and first-svn is a local copy of it, onto which you
> cherry-picked some extra patches.
Yeah, your guess is correct:
first-svn/trunk remote branch of the fist svn repos
second-svn/trunk remote branch of the second svn repos
first-svn local branch where first-svn/trunk is to be tracked
second-svn local branch where second-svn/trunk is to be tracked
> What I'm suggesting is that you think of your local branch (first-svn
> in this case, I guess) as *not* an svn branch at all. You never do
> any git-svn operations directly on this branch. In fact, rename it to
> master so you aren't tempted to get yourself into trouble.
I see. But currently, I have _two_ local branches and not only one, as
you suggested in your last post.
> Now, you've merged from first-svn/trunk and cherry-picked some extra
> stuff onto this branch, right? Good. Now you want to *merge* this
> branch into first-svn/trunk, producing just *one* new commit, and
> dcommit that into svn.
>
> git checkout first-svn/trunk
> # detaches the HEAD
> git merge master
> # produces a merge commit on the detached HEAD
> git svn dcommit
> # produces a *different* commit object on the first-svn/trunk branch
> # ...and moves HEAD to it.
>
> The newly-produced commit tells git that first-svn/trunk is now
> up-to-date with master. Note that the interim merge commit (produced
> by 'git merge') is never shared with *anyone*, so it's perfectly okay
> that we replace it with the next command.
Finally, this seems to work. Luckily, I've done the cherry-picking
not directly, but instead wrote a perl-script with instructions which
commits to pick and how to resolve the conflicts for specific commits.
I use copies of the repositories for this, so I can re-play the scenario
until the result fits the expectations.
With your explanation, I finally arrived at the _first_ work flow
that is able to push the results of the cherry-picking back to the
svn repositories. Having the branches described above, it goes
like this:
# first, retrieve what is available
#
git svn fetch first-svn
git svn fetch second-svn
# cherry-pick from second-svn to first-svn
#
git svn checkout first-svn
git cherry-pick sha1-from-second-svn # repeat as needed
git checkout first-svn/trunk
git merge --no-ff first-svn
git diff first-svn/trunk first-svn >changes.diff
git svn dcommit
# now do the same the other way around
#
git svn checkout second-svn
git cherry-pick sha1-from-first-svn # repeat as needed
git checkout second-svn/trunk
git merge --no-ff second-svn
git diff second-svn/trunk second-svn >changes.diff
git svn dcommit
But I am still somewhat confused:
git log -1 first-svn/trunk
says "Merge branch first-svn into HEAD". But this does not reflect
what I've actually done: I've picked _from_ second-svn and committed
that _to_ first-svn.
> What you probably thought you should do, given that the existing
> git-svn documentation says to do it, is more like this:
>
> # WRONG
> git checkout first-svn
> git cherry-pick some stuff
> git merge [perhaps -s ours] second-svn/trunk
> git svn dcommit
Almost... In addition, I was trying to "git svn rebase" before the
dcommit
> But the above will *change* every single commit you put on first-svn,
> because dcommit needs to *regenerate* all the commits after putting
> them into svn and getting them back again. This is essentially a
> rebase, and disrupts any merges you might have made from this branch
> to another one. Next time you merge, you'll get a zillion conflicts.
>
> > Ah! I thought I _have_ to "git svn rebase" before I dcommit, like I need
> > to "svn update" before I can do "svn commit".
>
> This is true and yet not true. The reason I don't have to ever use
> 'git svn rebase' is that 'git svn fetch' updates my first-svn/trunk
> branch, and then I quickly do a merge-then-dcommit on that branch. If
> I was to do a 'git svn rebase' first, nothing would happen, because
> svn doesn't change.
>
> This is important, since 'git svn dcommit' actually *does* do a 'git
> svn rebase' for you automatically, trying to be helpful.
What would happen if somebody else creates a new commit just after I
"git svn fetch" but before I dcommit? Guess, svn will not accept this
commit, because it is based on an outdated revision. How would I
get out from this situation?
> >> In general, 'git svn rebase' should be avoided for all the same
> >> reasons that 'git rebase' should be avoided. They're both great when
> >> used carefully, but they shouldn't be your main day-to-day activity.
> >
> > Unfortunately, all the howto's I could find recommend exactly that:
> > git-svn-rebase for getting commits from svn and dcommit for sending
> > commits to svn.
>
> Yeah, they're trying to keep things simple, at the cost of preventing
> you from doing anything complicated. I'm not smart enough to do both,
> so I'm just making things complicated for you here ;)
At least I could finally submit the cherries to the svn repositories.
That's a big step forward, although I still don't fully understand all
the details.
> As it happens, I wrote the git-svn chapter for the
> very-nearly-available new O'Reilly book "Version Control with Git." I
> gave the complicated solution there too.
Interesting. Do you have any information when it will be available?
> I'm eagerly awaiting the
> giant flames from people who actually wrote git-svn (and its
> documentation) and therefore are highly qualified to disagree with me.
>
> >> - 1 remote branch: git-svn-1
> >> - 1 remote branch: git-svn-2
> >> - 1 local branch: master
> >
> > I will try this one. But this will take a while, since my
> > cherry-picking was done criss-cross. Thus, I need to "rebase"
> > the cherries now to get them onto a single branch. Is there
> > a simple way to do that or do I have to redo the cherry-picking from
> > scratch?
>
> No no! Stop rebasing!
>
> You have a branch that looks the way you want, right?
Ummm, no.. I have _two_ branches:
first-svn: contains the cherries that I picked from second-svn. This
branch looks the way first-svn/trunk should be
second-svn: contains the cherries that I picked from first-svn. This
looks the way second-svn/trunk should be
Don't I need to rebase at least one of them if I want to "merge" those
two branches into a single one?
I have a hard time to adopt my mental model to the one-branch method for
some reason. OTOH, I can easily understand the multiple-branch method:
for every remote branch, I have a local branch on which I collect the
commits that should go to this remote.
> That means
> you're 99% of the way there. You just have to convince git that this
> branch and the svn branch are related to each other in the way they
> actually are.
>
> To do that, you just need to do is make a single merge commit on your
> svn remote branch that looks the way you want and merges from your
> existing branch, then do a single 'git svn dcommit'. Here's one way
> (assuming you want to make svn look like your new local branch):
>
> git checkout my-local-branch
> git merge -s ours svn-branch
> git checkout svn-branch
> git merge --no-ff my-local-branch
> git svn dcommit
>
> (If the occasionally-suggested '-s theirs' merge strategy existed, you
> could just do the last three steps using git merge -s theirs.)
>
> >> >> As long as you "git config merge.summary true" (to make the merge
> >> >> commit list all the commits it's merging)
> >>
> >> When you *merge* (as opposed to rebase or cherry-pick) into an svn
> >> branch, you only create a *single* svn commit that contains *all* the
> >> changes. The above config setting just makes the merge commit contain
> >> a list of all the commits it contains.
> >
> > But git will not use this information in any way, AFAIK. So this information
> > is only for the person who will do the next merge?
>
> In fact, it *only* affects the svn log. Otherwise svn log ends up
> with a useless commit that says "Merged from commit (giant hex
> string)", and you can't actually do anything with the giant hex string
> because svn doesn't know what it is.
OK. I just noticed the list is limited to 22 entries. Can this be
configured somehow to contain the complete list?
> > The people are not uncooperative. It is just that there's no way to
> > completely separate the public and private content.
>
> There is, if you're willing to do it. The usual way is two have two
> branches: public and private.
Well, my plan was to have one (generic) public repository that contains
templates instead of the localized information. Separating the
repositories is a security measure here.
Whether separate repositories or only different branches, conflicts
_are_ to be expected in this area.
> Whenever you make a change that you want to be public, you commit it
> on the public branch, then merge (git merge or svn merge, it doesn't
> matter) from public to private. If you want to make a private change,
> you just commit it directly to private.
>
> This way, you will always have the two sets of changes isolated, you
> never have to cherry-pick anything, and "git diff public private" is
> always a sensible thing to do.
Yeah, I see. OTOH, I'd rather avoid doing two steps in one go.
Currently, I have a hard time to get _one_ branch in sync. I'll come
back to the multiple-branch-thing as soon as I have mastered the
one-branch-thing ;-)
> (In fact, when I do this, I often don't share the private branch with
> anyone at all, which means it's safe to rebase. That means I can keep
> a clean set of patches against the public branch, and sort and
> rearrange or share them whenever I feel like it. This is useful in
> some cases. Rebasing isn't *always* bad :))
>
> >> If you're using cherry-pick for everything, there's no reason to use
> >> tricks like 'merge -s ours'. Just leave out the merging entirely and
> >> don't pretend that what you're doing is merging; it isn't. (You still
> >> don't need 'git svn rebase' for anything. Just checkout the branch
> >> you want to change, cherry-pick stuff into it, and 'git svn dcommit'
> >> if appropriate.)
> >
> > But then I have to do the book-keeping (what was already picked in which
> > direction) by myself?
>
> On branch b, 'git merge x' will always merge all the changes from the
> most recent merge of x into b (which might be a "-s ours" merge if you
> want), up to the tip of x. So if you don't commit any *new* private
> stuff to x, you can use merge. If you're intermixing the changes,
> you'll need to use cherry-pick. git won't attempt to track the
> cherry-picks for you (like eg. svnmerge will).
next prev parent reply other threads:[~2009-04-30 22:31 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-27 20:12 Trying to sync two svn repositories with git-svn (repost) Josef Wolf
2009-04-28 20:30 ` Josef Wolf
2009-04-28 20:53 ` Avery Pennarun
2009-04-28 22:37 ` Josef Wolf
2009-04-29 3:19 ` Avery Pennarun
2009-04-29 16:01 ` Josef Wolf
2009-04-29 18:13 ` Avery Pennarun
2009-04-29 22:37 ` Josef Wolf
2009-04-30 2:07 ` Avery Pennarun
2009-04-30 22:28 ` Josef Wolf [this message]
2009-04-30 22:59 ` Avery Pennarun
2009-05-01 14:28 ` Josef Wolf
2009-05-01 19:17 ` Avery Pennarun
2009-05-02 21:58 ` Josef Wolf
2009-05-04 15:58 ` Avery Pennarun
2009-05-04 21:14 ` Josef Wolf
2009-05-06 18:52 ` Josef Wolf
2009-05-06 19:23 ` Avery Pennarun
2009-05-06 22:50 ` Josef Wolf
2009-05-08 20:44 ` Avery Pennarun
2009-05-08 23:58 ` Josef Wolf
2009-05-13 12:09 ` Josef Wolf
2009-05-13 17:28 ` Avery Pennarun
2009-05-13 22:22 ` Josef Wolf
2009-05-14 6:35 ` Avery Pennarun
2009-05-14 21:41 ` Josef Wolf
2009-05-14 21:57 ` Avery Pennarun
2009-05-15 17:52 ` Josef Wolf
2009-05-15 19:05 ` Avery Pennarun
2009-05-17 11:24 ` Josef Wolf
2009-05-20 16:40 ` Josef Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090430222808.GH15420@raven.wolf.lan \
--to=jw@raven.inka.de \
--cc=apenwarr@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.