branchgit-svncherry-pickdcommit

`git svn dcommit` failing on a branch


I have been using git-svn to communicate with my company’s svn repo for a while now without any major headaches.

Today, the β€œheadache”-part changed dramatically:
I’ve been working on master/trunk pretty exclusively, and needed to merge most (but not all!) of those change-sets into a new svn-branch, that originated from a pre-existing svn-branch.

Basically this:

πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  master/trunk
 \
  \
   2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’                                        versioned-release

Should have become this:

πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  master/trunk
 \
  \
   2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’                                        versioned-release
                         \
                          \
                           1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’           new-versioned-release

Where πŸ’© are commits that shouldn’t be in the new-versioned-release, and xπŸ’ the wanted commits from the respective branches x.

So I did the following:

  1. git checkout -b versioned-release-svn remotes/versioned-release
  2. git svn branch new-versioned-release -m "Preparing for merge of XXX"
  3. git checkout -b new-versioned-release-svn remotes/new-versioned-release
  4. git cherry-pick ... for every 1πŸ’, resolving any conflicts on the way.

Because I wanted to be sure I was really going to target the correct branch on the repo, I then ran git svn dcommit --dry-run which did not yield any errors or warnings, but told me…

Committing to svn://username@$repo-host/$repo-name/$path/branches/new-versioned-release ...

…followed by a couple of diff-tree lines.

So I attempted to omit the --dry-run and half way through the commits ended up with…

Item already exists in filesystem: File already exists: filesystem '/data/subvroot/$repo-name/db', transaction '20856-g3m', path '/$path/branches/new-versioned-release/some-directory' at /usr/libexec/git-core/git-svn line 862

…and a bunch of unstaged changes.

Apart from the obvious β€” β€œWTF?!?” and β€œHow do I get out of this mess without losing everything I did?” β€” I have two questions:

  1. Assuming I was back to before git svn dcommit: How do I get my local branch dcommit to its planned destination?
  2. By now it seems obvious, that this wasn’t the right way to achieve what I wanted…but how should I have done it, instead?

Everything I found for the error-message, that somehow resembled my situation, so far was this other stack overflow question and the proposed solution of β€œsomehow […] to blow away the .git/svn metadata directory” doesn’t resonate quite that well with me…


Solution

  • Someone just up–voted my old question, so I thought I’d share how I do that nowadays.

    It works really quite well.

    Assuming the git repository has been created using

    git svn clone \
        --prefix svn/ \
        --stdlayout \
        svn://username@$repo-host/$repo-name/$path
        $git_repo_name
    

    change into the git repo, and there run

    git checkout svn/versioned-release
    git svn branch new-versioned-release
    

    This will result in the following history on the SVN server:

    πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  trunk
     \
      \
       2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’                                        versioned-release
                              \
                               \
                                3⭐️                                    new-versioned-release
    

    Now I’d run

    git checkout svn/new-versioned-release
    git checkout -b new-versioned-release
    
    # resulting in the following **local** history:
    #
    # πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  master (tracks 'svn/trunk')
    #  \
    #   \
    #    2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’--3⭐️                         new-versioned-release (tracks 'svn/new-versioned-release')
    

    This is the foundation for achieving what I wanted.

    There is one additional commit, because branching in SVN doesn’t work the same way as in Git: creating a branch always means a new revision, (aka commit) and that’s where the 3⭐️ comes from. It doesn’t really matter, but it’s there.

    I can now git cherry-pick all the 1πŸ’s, ending up with this local history:

    πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  master (tracks 'svn/trunk')
     \
      \
       2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’--3⭐️--1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’  new-versioned-release (tracks 'svn/new-versioned-release')
    

    When I now git svn dcommit while sitting on new-versioned-release in git, the history on the SVN server looks like what I wanted to end up with:

    πŸ’---πŸ’©---πŸ’©---πŸ’©--1πŸ’--1πŸ’---πŸ’©--1πŸ’---πŸ’©---πŸ’©--1πŸ’--1πŸ’--1πŸ’---πŸ’©  trunk
     \
      \
       2πŸ’--2πŸ’--2πŸ’--2πŸ’--2πŸ’                                        versioned-release
                              \
                               \
                                3⭐️--1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’--1πŸ’    new-versioned-release
    

    The only difference being that additional 3⭐️ from creating the third SVN branch.