Skip to content

Instantly share code, notes, and snippets.

@rickyah
Last active April 16, 2024 18:16
Show Gist options
  • Save rickyah/7bc2de953ce42ba07116 to your computer and use it in GitHub Desktop.
Save rickyah/7bc2de953ce42ba07116 to your computer and use it in GitHub Desktop.
A simple guide to git-svn

Getting Started with Git SVN

Introduction

git svn is a git command that allows using git to interact with Subversion repositories. git svn is part of git, meaning that is NOT a plugin but actually bundled with your git installation. SourceTree also happens to support this command so you can use it with your usual workflow.

Important You need to use the command git svn without the hyphen '-'.

Disclaimer This guide was written circa 2015, when working on a project where it was required to use SVN. As back in the day I was more proficient and confortable using git workflows (specifically fast and multiple local branches), in order to replicate some of those workflow with SVN I started using this command. Of course I faced some issues, so this document is just a dump of my knowledge and hopefully a helping guide in case you face the same problems as I did.

However, it is not an exhaustive guide, nor it is updated anymore, so please, if you find something wrong, please leave a messge.

I hope this guide may be helpful to you. Enjoy!

Cloning the SVN repository

You need to create a new local copy of the repository with the command

git svn clone SVN_REPO_ROOT_URL [DEST_FOLDER_PATH] -T TRUNK_REPO_PATH -t TAGS_REPO_PATH -b BRANCHES_REPO_PATH

If your SVN repository follows the standard layout (trunk, branches, tags folders) you can save some typing:

git svn clone -s SVN_REPO_ROOT_URL [DEST_FOLDER_PATH]

git svn clone checks out each SVN revision, one by one, and makes a git commit in your local repository in order to recreate the history. If the SVN repository has a lot of commits this will take a while, so you may want to grab a coffee.

When the command is finished you will have a full fledged git repository with a local branch called master that trackes the trunk branch in the SVN repository.

If the SVN repository has a long history, the git svn clone operation can crash or hang (you'll notice the hang because the progress will stall, just kill the process with CTRL-C). If this happens, do not worry: the git repository has been created, but there is some SVN history yet to be retrieved from the server. To resume the operation, just change to the git repository's folder and issue the command git svn fetch.

Getting the latest changes from SVN

The equivalent to git pull is the command git svn rebase.

This retrieves all the changes from the SVN repository and applies them on top of your local commits in your current branch. This works like, you know, a rebase between two branches :)

You can also use git svn fetch to retrieve the changes from the SVN repository but without applying them to your local branch.

Local work

Just use your local git repository as a normal git repo, with the normal git commands

  • git add FILE and git checkout -- FILE To stage/unstage a file
  • git commit To save your changes. Those commits will be local and will not be "pushed" to the SVN repo
  • git stash and git stash pop Hell yeah! Stashes are back!
  • git reset HEAD --hard Revert all your local changes
  • git log Access all the history in the repository
  • git rebase -i Yep, you can squash all the commits! (as usual be SUPER CAREFULL with this one)
  • git branch Yes! you can create local branches! But remember to keep the history linear!

Pushing local changes to SVN

git svn dcommit --rmdir will create a SVN commit for each of your local git commits. As with SVN, your local git history must be in sync with the latest changes in the SVN repository, so if the command fails, try performing a git svn rebase first.

Side note

Your local git commits will be rewritten when using the command git svn dcommit. This command will add a text to the git commit's message referencing the SVN revision created in the SVN server, which is VERY useful. However, adding a new text requires modifying an existing commit's message which can't actually be done: git commits are inmutable. The solution is create a new commit with the same contents and the new message, but it is technically a new commit anyway (i.e. the git commit's SHA1 will change)

Caveats

"Subversion is a system that is far less sophisticated than Git" so you can't use all the full power of git without messing up the history in the Subversion server. Fortunately the rules are very simple:

Keep the history linear

That's it.

This means you can make all kind of crazy local operations: branches, removing/reordering/squashing commits, move the history around, delete commits, etc anything but merges.

Local merges

Do not merge your local branches, if you need to reintegrate the history of local branches use git rebase instead.

When you perform a merge, a merge commit is created. The particular thing about merge commits is that they have two parents, and that makes the history non-linear. Non-linear history will confuse SVN in the case you "push" a merge commit to the repository.

However do not worry: you won't break anything if you "push" a git merge commit to SVN.

If you do so, when the git merge commit is sent to the svn server it will contain all the changes of all commits for that merge, so you will lose the history of those commits, but not the changes in your code.

Handling empty folders properly

git does not recognice the concept of folders, it just works with files and their filepaths. This means git does not track empty folders. SVN, however, does. Using git svn means that, by default, any change you do involving empty folders with git will not be propagated to SVN.
Fortunately the --rmdir flag corrects this issue, and makes git remove an empty folder in SVN if you remove the last file inside of it. Unfortunatelly it does not removes existing empty folders, you need to do it manually

To avoid needing to issue the flag each time you do a dcommit, or to play it safe if you are using a git GUI tool (like SourceTree) you need to set this behaviour as default, just issue the command:

git config --global svn.rmdir true

This changes your .gitconfig file and adds these lines:

[svn]
rmdir = true

Be careful if you issue the command git clean -d. That will remove all untracked files including folders that should be kept empty for SVN. If you need to generate againg the empty folders tracked by SVN use the command git svn mkdirs.

In practices this means that if you want to cleanup your workspace from untracked files and folders you should always use both commands:

git clean -fd && git svn mkdirs

Cloning really big SVN repositories

If you SVN repo history is really really big this operation could take hours, as git svn needs to rebuild the complete history of the SVN repo. Fortunately you only need to clone the SVN repo once; as with any other git repository you can just copy the repo folder to other collaborators. Copying the folder to multiple computers will be quicker that just cloning big SVN repos from scratch.

About commits and SHA1

As git commits created for git svn are local, the SHA1 ids for git commits is only work locally. This means that you can't use a SHA1 to reference a commit for another person because the same commit will have a diferent SHA1 in each machine. You need to rely in svn revision number. The number is appended to the commit message when you push to the SVN server

You can use the SHA1 for local operations though (show/diff an specific commit, cherry-picks and resets, etc)

Troubleshooting

MacOS & Perl - Can't locate SVN/Core.pm in @INC

git svn command is implemented as a Perl script. In newer versions of MacOS, system installed Perl do not include the SVN::Core module, so you have to either:

Also, remember that Subversion must also be installed on the system.

Linux - git: 'svn' is not a git command

@graue70 pointed out that on linux you need to install the git-svn command with sudo apt install git-svn The command git svn rebase throws an error similar to this:

  Checksum mismatch: <path_to_file> <some_kind_of_sha1>
  expected: <checksum_number_1>
    got: <checksum_number_2>

git svn rebase command issues a checksum mismatch error

The solution to this problem is reset svn to the revision when the troubled file got modified for the last time, and do a git svn fetch so the SVN history is restored. The commands to perform the SVN reset are:

  • git log -1 -- <path_to_file> (copy the SVN revision number that appear in the commit message)
  • git svn reset <revision_number>
  • git svn fetch

You should be able to push/pull data from SVN again

File was not found in commit

When you try to fetch or pull from SVN you get an error similar to this

<file_path> was not found in commit <hash>

This means that a revision in SVN is trying to modify a file that for some reason doesn't exists in your local copy. The best way to get rid of this error is force a fetch ignoring the path of that file and it will updated to its status in the latest SVN revision:

  • git svn fetch --ignore-paths <regex>

(thanks @rykus0 for pointing out that --ignore-paths actually accepts a regex, not a file-path)

References

@notionquest
Copy link

How to give multiple files in --ignore-paths? I have tried the below. It is not working.
git svn fetch --ignore-paths file1,file2

@uvwild
Copy link

uvwild commented Mar 27, 2017

The ignore-paths option leads into a scenario which alternates between 2 files....
back and forth....
any idea how to get past this?

@Rykus0
Copy link

Rykus0 commented Jul 5, 2017

@notionquest --ignore-paths accepts a regular expression. So to ignore 2 paths, you could pass something like this: --ignore-paths=(pattern1|pattern2)

Note that it is regex patterns and NOT explicit filenames. So if you pass --ignore-paths=myFile it should also ignore files named myFilename, myFiles, myFile2, etc.

@rickyah
Copy link
Author

rickyah commented Jan 8, 2018

Been some time since I needed to use git-svn, but I was not aware that --ignore-paths required a regex. Either it was changed or I got really lucky when fixing the problems using that argument. Anyway, thanks for the insight @Rykus0

@Dhananjay1991
Copy link

In migration from svn to git how can we verify that "git svn rebase" executed successfully.I mean after "git svn rebase" the content of git repository and svn should be same.Is there any procedure to verify both folders in svn and the git repository locally created are same.Is there any command available then it will be very helpful to me

@isupovs
Copy link

isupovs commented Jun 29, 2018

Hi there! Could I use git-svn on an already cloned repo or should I do clone with git svn clone?

@rdisipio
Copy link

rdisipio commented Apr 8, 2019

How do I just move the code without having to go through the revision history?

@koepferl
Copy link

Hi, I have a problem. I get the command

git: 'svn' is not a git command. See 'git --help'.

Did you mean one of these?
fsck
mv
show

@CableGuy67
Copy link

Hi, I have a problem. I get the command

git: 'svn' is not a git command. See 'git --help'.

Did you mean one of these?
fsck
mv
show

The answer to something that sounds very similar was updated recently so perhaps it would help.
https://stackoverflow.com/questions/60869682/git-svn-is-not-a-git-command-mac

@ppbpdx
Copy link

ppbpdx commented Dec 8, 2020

If you are on a current version of Mac OS you will have issues with git svn. I followed these steps on Catalina 10.15.7 and it worked for me.

Homebrew/homebrew-core#52490 (comment)

@Gelma
Copy link

Gelma commented Dec 10, 2020

Thanks a lot.

Please fix "becasue".

Thanks again,
Gelma

@hemanthecan
Copy link

I got the same issue for my linux machine could anyone suggest me the best solution as it is critical

git: 'svn' is not a git command. See 'git --help'.

Did you mean one of these?
fsck
mv
show

@graue70
Copy link

graue70 commented Apr 27, 2021

I got the same issue for my linux machine could anyone suggest me the best solution as it is critical

git: 'svn' is not a git command. See 'git --help'.

Did you mean one of these?
fsck
mv
show

The package git-svn is not installed on your machine. You need to install it first. For example, on ubuntu you need to run sudo apt install git-svn.

@rickyah
Copy link
Author

rickyah commented Apr 27, 2021

Hi all. I've updated the guide so it points out that you have to use git svn (without the hyphen) and some troubleshooting for MacOS and Linux

It makes me happy that this guide is still useful to some of you.

@graue70
Copy link

graue70 commented Apr 27, 2021

Hi all. I've updated the guide so it points out that you have to use git svn (without the hyphen) and some troubleshooting for MacOS and Linux

It makes me happy that this guide is still useful to some of you.

The added sentence in the Linux troubleshooting section should go before the next header.

@rickyah
Copy link
Author

rickyah commented Apr 28, 2021

Thanks @graue70

@graue70
Copy link

graue70 commented Apr 28, 2021

There is still something messed up with the sentences being mashed together.

@pichocki
Copy link

pichocki commented Jul 20, 2021

I am "desperately" trying to migrate my MS TFS repositories to SVN, and I understand that this is only possible via GIT. (Yes, at this time, I prefer SVN over GIT. This may change, but not right now.)

I already succeeded to migrate my TFS repositories to local GIT repositories on my development PC, but after that I am stuck. I have tested "all" the descriptions I could find, but none of them actually worked. Always git svn dcommit reports an error.

The farthest I could get, was with this description http://www.twisterrob.net/blog/2017/12/import-git-repo-to-svn-folder.html which actually works if I copy it line by line.

If I do it with my own repositories (which have been cloned from TFS), I cannot dcommit them, instead git svn dcommit reports an error
"No changes
(id of original GIT repo first commit) == <(id of original GIT repo first commit)
Unable to extract revision information from commit (id of original GIT repo second commit)"

Is there any way to "repair" this? Glad for any advice! Thank you!

@TooMuchBlue
Copy link

I am "desperately" trying to migrate my MS TFS repositories to SVN, and I understand that this is only possible via GIT. (Yes, at this time, I prefer SVN over GIT. This may change, but not right now.)

I already succeeded to migrate my TFS repositories to local GIT repositories on my development PC, but after that I am stuck. I have tested "all" the descriptions I could find, but none of them actually worked. Always git svn dcommit reports an error.

I'm in a very similar situation. Have you made any headway on this?

In my case, the TFS repository is gone. The git repo is linear -- no branching.

The target SVN repo has 15+ years of commits, and it's not practical to fetch the entire thing. Instead, I created a folder in SVN where the content will live, and then specified only this path in --include-paths. Init and fetch both seem to succeed, but without any output. Then git svn info complains "Unable to determine upstream SVN information" and I wonder whether it ever connected at all.

@pichocki
Copy link

Actually, no, I did not succeed in this. Finally, I gave up and decided to go with GIT - especially after I saw that Visual Studio has native support for GIT. I thought that it would pay off better to work into GIT than to try and try and try - with uncertain outcome.

@tsangsir
Copy link

A dumb question but unable to google the answer... Is it needed to have subversion client to use git-svn? Actually I was trying to use git-svn because I want to clone a subversion repo on a computer without subversion.

@jacekkowalczyk82
Copy link

nice, thank you

@Tey
Copy link

Tey commented Feb 26, 2023

If I do it with my own repositories (which have been cloned from TFS), I cannot dcommit them, instead git svn dcommit reports an error
"No changes
(id of original GIT repo first commit) == <(id of original GIT repo first commit)
Unable to extract revision information from commit (id of original GIT repo second commit)"

Is there any way to "repair" this? Glad for any advice! Thank you!

The problem is git-svn cannot commit empty git commits to svn, so it fails eventually that way. For those stuck there, what worked for me was running git svn rebase first to start from a clean state, and then, removing the empty commits using a command like:

git filter-branch --prune-empty --tag-name-filter cat -- --all

You might want to restrict the commits to filter to those that still need to be sent to svn (replacing --all with ${SHA1}..HEAD for instance).

@VeroGHub
Copy link

VeroGHub commented Nov 3, 2023

hola buenos dias, existira alguna forma de clonar el repositorio svn pero que solo traiga la ultima revision???, no me interesa traer todo el log, solo el ultimo, muchas gracias.

@steinhh
Copy link

steinhh commented Jan 8, 2024

@VeroGHub If I understand you correctly: just create an empty git repository, then copy all the files from the SVN working directory, then add & commit all the files in one go.

@IntuloSoft
Copy link

Great guide!

I have an extra question regarding branches. In SVN it is possible to create branches on subfolders and put them in your default branches location. I'll give an example to clarify:

Repo structure
trunk/
subfolder1/
subsubfolder1/
subfolder2/
branches/
branchname/
subsubfolder1 -> branch on subfolder
tags/

How do you handle this in git-svn? In this case, it should be possible to define branches by branch location on SVN (branches/testbranch) and from where the branch has been taken (subfolder1).

Has anyone an idea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment