202

I'm using git-svn to work against my company's central Subversion repository. We've recently created a new feature branch in the central repo.

How do I tell Git about it? When I run git branch -r I can only see the branches that existed when I ran fetch against the Subversion repo to initialize my Git repo?

Lii
  • 11,553
  • 8
  • 64
  • 88
Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • Answers from here: http://stackoverflow.com/questions/13376917/add-git-branch-after-initial-fetch-in-the-same-svn-remote might also be useful. – Tomasz Gandor Jun 27 '16 at 10:06

9 Answers9

305

You can manually add the remote branch,

git config --add svn-remote.newbranch.url https://svn/path_to_newbranch/
git config --add svn-remote.newbranch.fetch :refs/remotes/newbranch
git svn fetch newbranch [-r<rev>]
git checkout -b local-newbranch -t newbranch
git svn rebase newbranch
vjangus
  • 3,464
  • 1
  • 20
  • 13
  • 3
    just adding this link to the docs as a reference http://www.kernel.org/pub/software/scm/git/docs/git-svn.html – slf Aug 22 '11 at 15:34
  • That link to the docs is down. I looked all over for a new link, but I can't find any "official" git-svn docs. Does anyone have a good link to replace this with? – Mu Mind Feb 09 '12 at 16:54
  • 1
    From .git/config it is quite easy to understand how remote branches can be configured from single / multiple repositories. – Mikael Lepistö Feb 11 '12 at 13:48
  • isn't the whole point of --stdlayout so that git svn can know some of these things. IMO There should be a git svn command which does the first 3 all in one shot based off --stdlayout – jrwren Apr 12 '12 at 13:05
  • 6
    If I could upvote this like eight times, I would. Finally, a way to add an svn branch that's added in a nonstandard location! – Tim Keating Jun 27 '12 at 01:25
  • 1
    The branch doesn't seem to be based on trunk/master, the first commit is the copy. Can you rebase the newbranch on the commit in trunk where it is copied from? – Erik Martino Jun 28 '13 at 06:36
  • 1
    Unfortunately, this looses svn branch history. E.g. your `git blame` will render useless, amongst other stuff. See [MatrixFrog's answer](http://stackoverflow.com/a/4416172/531179) for a better solution. – ulidtko Aug 29 '13 at 14:39
  • This approach may be required if the branch location is in a non-standard location, but if you use standard locations and pulled in the branches that already existed with the initial clone, then git svn fetch is all you need (as suggested in the other answer below). Note you need 'git svn fetch' explicitly not just 'git svn rebase'. – ajsutton Oct 17 '13 at 13:39
  • 8
    I get `fatal: Cannot setup tracking information; starting point 'newbranch' is not a branch.` at the git checkout step. – phpguru Mar 03 '14 at 22:20
  • 19
    @phpguru Try removing the -t option flag so it becomes 'git checkout -b local-newbranch newbranch' don't forget to include the remote's prefix to newbranch (ex. origin/newbranch). – mj1531 May 28 '14 at 17:53
  • 1
    minor point, but when this answer mentions [-r], I had to do `-r21000:HEAD` – djKianoosh Dec 15 '14 at 19:03
  • 1
    The 4th command no longer works on current versions of Git. Omit "-t" and you should be OK. See here for details: http://stackoverflow.com/q/19712735/745575 – apokluda May 18 '17 at 20:41
105

If you want to track ALL the remote svn branches, then the solution is as simple as:

git svn fetch

This will fetch ALL the remote branches that have not been fetched yet.

Extra tip: if you checked out only the trunk at first, and later you want to track ALL branches, then edit .git/config to look like this and re-run git svn fetch:

[svn-remote "svn"]
        url = https://svn/path_to_repo_root/
        fetch = path_to_trunk:refs/remotes/git-svn
        branches = path_to_branches/*:refs/remotes/*

The key points are url should point to the repository root, and the paths defined in fetch and branches should be relative to url.

If you want to fetch only specific branches instead of ALL, there is a nice example in git svn --help:

[svn-remote "huge-project"]
        url = http://server.org/svn
        fetch = trunk/src:refs/remotes/trunk
        branches = branches/{red,green}/src:refs/remotes/branches/*
        tags = tags/{1.0,2.0}/src:refs/remotes/tags/*

With older versions of git-svn, once you specified branches like this, you might not be able to get new branches with git svn fetch. One workaround is adding more fetch lines, like this:

[svn-remote "huge-project"]
        url = http://server.org/svn
        fetch = trunk/src:refs/remotes/trunk
        fetch = branches/blue:refs/remotes/branches/blue
        fetch = branches/yellow:refs/remotes/branches/yellow
        branches = branches/{red,green}/src:refs/remotes/branches/*

Another workaround by @AndyEstes: edit .git/svn/.metadata and change the value of branches-maxRev or tags-maxRev to a revision before any newly-specified branches or tags were created. Once you've done this, run git svn fetch to track the new svn remote branch.

janos
  • 120,954
  • 29
  • 226
  • 236
  • I am also unable to change the branches line and need to use additional fetch lines. – sandos Jan 08 '13 at 10:51
  • I like this solution better because, this one was able to show me nice graph in git also was able to see the history in files. With the accepted solution, it treated each branch with its own history and only showed the last commit (one that created the branch) and I was not able to see file change history. Only problem I have is not being able to add the branches later as you indicated.. I hope this get resolved soon. – bond Apr 08 '13 at 15:43
  • 1
    If you have already fetched the revision to which performed svn branching before you set those settings, you might want to do git svn reset. – kcm1700 Jul 18 '13 at 04:06
  • 5
    Editing ```.git/svn/.metadata``` was very helpful! I was adding extra branches in my ```.git/config```, which ```git svn fetch``` didn't pick up on -- because the metadata revision number was "too far ahead". In one case, only the last commit from a branch was fetched. I manually got rid of the faulty branch (renamed ```.git/svn/refs/remotes/svn/qa/XYZ``` to ```.git/svn/refs/remotes/svn/qa/XYZ~```, dropped its existence in ```.git/packed-refs```, etc)... picked an "earlier" revision number for the metadata... ran ```git svn fetch``` to finally get a full history w/ correct, connected graph. – starlocke Sep 20 '13 at 16:57
  • Thanks, @AndyEstes. I needed to do this to get git-svn to find a branch I wanted to add (when my git-svn repo was already fully up to date with SVN, but did not yet include the branch). – Conrad Meyer Oct 06 '13 at 19:14
  • 10
    THIS SHOULD BE THE ACCEPTED ANSWER! @janos, you just saved me hours of headache! If you ever come to India, I'll take you out for a beer! – Roopesh Shenoy Oct 22 '13 at 21:09
  • Does anyone know if you can have whitespace or subfolders in the branches like this? branches = branches/{58/red,green 3}/src:refs/remotes/branches/* I'm getting a 'invalid pattern in' error when I try to fetch. – Richard Jul 15 '14 at 13:42
  • 1
    Or: `git svn fetch --all`. – kenorb Mar 18 '15 at 00:15
  • This was exactly what I needed for dealing with an SVN repository where the "trunk" is also in the branches folder. Looks like setting up the trunk to point to the exact path and then doing the {} for limiting the branches that are pulled should work. – AJ Henderson May 12 '16 at 18:46
  • Changing tags-maxrev is what worked for me to pick up new branches. Thanks! – caleb c. Nov 06 '17 at 15:17
54

It appears I just needed to git svn fetch; somehow I had convinced myself that would fetch the entire repo instead of just the changes.

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • 7
    @mitjak Why is it not the correct answer, if it's the solution? I don't understand the subtlety of the response. – rholmes Mar 18 '11 at 19:10
  • 1
    'a solution' maybe not 'the solution' – slf Aug 22 '11 at 15:30
  • 1
    @rholmes: I'm pretty sure mitjak means that that's the solution to your problem but not the answer to the question you asked. (Because you asked the wrong question; as you misinterpreted the issue at the time.) – aDev Jun 19 '12 at 20:17
  • This works when branch existed at the moment you cloned svn repository into git. It will not work if branch in svn repository was created afterwards. – Petr Gladkikh Jun 22 '12 at 07:46
  • 3
    It works fine when the branch was created after the clone, I do it all the time. – Tim Gautier Jul 16 '12 at 15:20
  • This is what helped me, but neither this nor the accepted answer is complete. This answer assumes the setup is already correct, while the accepted answer assumes that it isn't. A complete answer wouldn't assume either. – Jasper Jun 04 '14 at 15:38
15

Maybe I messed it up somehow but I followed the instructions in vjangus' answer and it almost worked. The only problem was that newbranch didn't appear to be branched from the trunk. In gitk, it was kind of "floating" all on its own; it had no common ancestor with the trunk.

The solution to this was:

  1. Find the SHA1 of the last commit that happened on trunk before the branch was created.
  2. Find the SHA1 of the first commit on the new branch (message is probably "Created new branch, copied from trunk@12345" or something)
  3. git diff-tree <sha1 from step 1> <sha1 from step 2> -- there should be no output. If there is output, you may have selected the wrong commits.
  4. git checkout local-newbranch then git rebase <sha1 from step 1>. This will rebase local-newbranch onto the new tree but remotes/newbranch will still be disconnected.
  5. Go to the file .git/refs/remotes/newbranch and edit it to contain the full SHA1 of the new commit (on the rebased newbranch) that corresponds to the old commit it's currently pointing at. (Or maybe use git-update-ref refs/remotes/newbranch <new-SHA>. Thank you inger.)
  6. The next time you git svn dcommit to newbranch, you'll get a bunch of messages about it updating some log. This is normal I think.

I recommend keeping gitk --all open the whole time and refreshing it often to keep track of what you're doing. I'm still sort of new to git and git svn so please suggest improvements to this method.

Tyler
  • 21,762
  • 11
  • 61
  • 90
  • 2
    Thanks, this sounds useful. About 5. probably 'git-update-ref refs/remotes/newbranch ' is the safer option. – inger Jan 27 '11 at 23:38
  • Just tried vjangus' way again and it worked perfectly. I'll leave this here anyway since it might be valuable to someone... – Tyler Jan 28 '11 at 21:45
  • 1
    vjangus solution always creates the new branch disconnected from the trunk. I assume this is because of the way SVN itself has no clue on how the actual content is copied around. – bogdan.mustiata Aug 31 '11 at 13:45
  • My experience with a large git-svn repo is that svn branches are always created in git detached from the trunk. There ought to be some way to connect them, but I haven't taken the time to figure it out. AFAIK, you can't rebase the git branch that is connected to the svn branch, because that will mess up the dcommit logic. We've just learned to live with it. – Spencer Mar 02 '12 at 14:10
7

A simplification of vjangus' answer:

If you're using the standard layout in SVN and have done the usual svn init, git-svn will do the config stuff for you. Just:

  1. Find branch-copy revision in SVN
  2. Fetch that revision with git-svn
  3. Create new local branch tracking remote

An example. SVN url is svn+ssh://gil@svn.myplace.com/repo. SVN branch I'm looking for is newbranch. Local git branch (tracking remote newbranch) will be git-newbranch.

Step 1: find the branch-copy revision

    # svn log --stop-on-copy svn+ssh://gil@svn.myplace.com/repo/branches/newbranch | tail -4
    r7802 | someone | 2014-03-21 18:54:58 +0000 (Fri, 21 Mar 2014) | 1 line

    branching HEAD to newbranch
    ------------------------------------------------------------------------

So the branch point in SVN is revision 7802.

Step 2: Fetch the revision

    # git svn fetch -r 7802
    Found possible branch point: svn+ssh://gil@svn.myplace.com/repo/trunk => svn+ssh://gil@svn.myplace.com/repo/branches/newbranch, 7801
    Found branch parent: (refs/remotes/trunk) 8dcf3c5793ff1a8a79dc94d268c91c2bf388894a
    Following parent with do_switch
    Successfully followed parent
    r7802 = 9bbd4194041675ca5c9c6f3917e05ca5654a8a1e (refs/remotes/newbranch)

git-svn did all the work and now knows about the remote:

    # git show-ref | grep newbranch
    2df23af4733f36f5ad3c14cc1fa582ceeb3edb5c refs/remotes/newbranch

Step 3: Create your new local branch tracking the remote one:

    # git checkout -b git-newbranch -t newbranch
    Checking out files: 100% (413/413), done.
    Branch git-newbranch set up to track local ref refs/remotes/newbranch.
    Switched to a new branch 'git-newbranch'
jpaugh
  • 6,634
  • 4
  • 38
  • 90
Gil Hamilton
  • 11,973
  • 28
  • 51
  • Following this **finally** allowed me to understand (`show-ref` is invaluable)! For anyone stuck with wrongly referencing remote branches, you can delete them (I had to do `git branch -d newbranch` and then force remove the ref dir in `.git/svn/refs/remotes/newbranch`) and then start over at step 2 (above). – tutuDajuju Dec 18 '14 at 06:36
5

I have not found any documentation about this feature, but looks like git svn configuration supports multiple fetch entries. This way you can also add branches separately without need to add another remote svn repository entry to your config nor using wildcards to get all branches of certain directory.

Assume that your SVN tree is really nasty having lots of branches without any logic how they are located, e.g. having branches and sub-directories containing more branched.

i.e.

trunk
branches
  -> branch1
  -> sub-dir1
    -> branch2
    -> branch3
  -> sub-dir2
    -> branch4
    -> sub-dir3
      -> branchX 
<... hundreds more ...>

and you just want to hand pick some of the branches to be included to your git repository.

You may first init your repository with only trunk without any additional branches:

git svn clone -r 10000:HEAD https://svn.com/MyRepo myrepo --prefix=svn/ --trunk=trunk 

After that you should see following configuration:

localhost: elhigu$ git config --get-regexp "svn-remote."
svn-remote.svn.url https://svn.com/MyRepo
svn-remote.svn.fetch trunk:refs/remotes/svn/trunk

when ever you want to fetch new branch from MyRepo you can just add new fetch entries to configuration by:

git config --add svn-remote.svn.fetch branches/sub-dir2/branch4:refs/remotes/svn/branches/sub-dir2/branch4

Or you may edit the same configuration in .git/config

To fetch the new branches after adding them to config just run:

git svn fetch -r 10000:HEAD

[Edit] Sometimes it seems to be necessary to run fetch with --all parameter to fetch newly added branches:

git svn fetch --all -r 10000:HEAD
Mikael Lepistö
  • 18,909
  • 3
  • 68
  • 70
4

Instead of dealing with the git-svn quirks you may try SubGit.

One has to install SubGit into Subversion repository. After that one can use standard git workflow instead of using special git-svn commands:

  1. Pushing new commits:

    git-svn:

    $ git commit
    $ git svn rebase
    $ git svn dcommit
    

    SubGit:

    $ git commit
    $ git push
    
  2. Fetching incoming changes

    git-svn:

    $ git svn rebase
    

    SubGit:

    $ git pull [--rebase]
    
  3. Creating a new branch:

    git-svn:

    $ git svn branch foo
    $ git checkout -b foo -t remotes/foo
    $ git commit
    $ git svn dcommit
    

    SubGit:

    $ git checkout -b foo
    $ git commit
    $ git push
    

See SubGit documentation for more details.

vadishev
  • 2,979
  • 20
  • 28
  • 1
    SubGit has the disadvantage that it creates two repositories - one svn, and one "shadow" git repository. This might be a problem for huge SVN repositories... – Udo Sep 25 '12 at 17:56
  • @Udo if SVN repository has a few projects, one may specify just one of them and synchronize it with Git repository. In this case there's no need to convert the whole Subversion repository into Git. But if one has a huge SVN project in this repository, one may convert not the whole history of this repository but the history starting from some minimal revision. This allows to decrease the size of translated Git repository. – vadishev Sep 26 '12 at 13:53
  • 1
    @Udo -- any company not willing to buy their repository server a hard drive has their priorities messed up. But most places with huge repositories take their repositories pretty seriously, and the disk space requirements for repositories are generally not a major issue, even for companies with decades of history and tens of millions of lines of code and hundreds of thousands of revisions. It's the company's most concrete form of their core intellectual assets, and disk space is pretty inexpensive. It might trigger a need to upgrade a RAID controller, but even so, the gain in productivity... – Bob Kerns Oct 04 '12 at 15:35
  • @Bob Kerns - The point is that "size wise" SVN and Git and not compatible. It's not a question of disk storage or so. But you can work with a huge SVN repository because usually you need to checkout out only a few files/projects. But you can't clone a huge Git repository - it doesn't make fun at least ;-) By "huge" I mean several Gigs. – Udo Oct 31 '12 at 14:00
2

To add to vjangus' answer, which helped me, I also found it useful to add use git grafts to tie the branches to the trunk at the appropriate point - allowing git to see the history and perform merges correctly.

This is simply a case of adding a line to .git/info/grafts with the hashes:

<initial branch commit> <parent commit in trunk>

eg.

378b0ae0902f5c2d2ba230c429a47698810532e5 6c7144991381ce347d4e563e9912465700be0638

Credit to http://evan-tech.livejournal.com/255341.html

(I'd add this as a comment, but I've not enough reputation.)

Haddon CD.
  • 169
  • 8
0

If you don't check out with a valid layout, you won't be able to checkout a remote branch.

This is what I do:

git svn init -s <svn path with no trunk> local_repo
cd local_repo
git svn fetch 
## wait

After that, you can switch to a remote branch:

git checkout --track -b branch_name branch_name

Then you will automatically be switched to your branch.

MikeHoss
  • 1,477
  • 4
  • 18
  • 35