Git-svn

From Git SCM Wiki
(Difference between revisions)
Jump to: navigation, search
(checkout / clone, log)
 
(43 intermediate revisions by one user not shown)
Line 1: Line 1:
This tutorial collects information for users of git as svn client, using [http://www.kernel.org/pub/software/scm/git/docs/git-svn.html git-svn]. Please consider reading [[GitSvnCrashCourse]], and the [[Media:Git-svn-cheatsheet.pdf|git-svn cheatsheet]]. As Git is distributed, there is no serial version numbering, but hashes for commits (aka change sets) are used.
+
{{DISPLAYTITLE:git-svn}}
 +
This tutorial collects information for users of git as subversion client, using git-svn. As Git is distributed, commits (aka change sets) are referenced by hashes instead of svn's serial version numbers. Git tracks contents, not files or directories. Consider to use a real svn client to rename directories, as git-svn produces a lot of renames in svn, instead of one like the original. git-svn is not a good tool to convert from svn to git, see [[Interfaces, frontends, and tools#Subversion | here for better options]].
  
 
__TOC__
 
__TOC__
  
== checkout / clone, log ==
+
== checkout / clone, log, configure basics ==
  git svn clone -r 400:HEAD https://svn.whatebber.org/repo/trunk folder # choose a recent commit
+
<pre>
 +
  git svn clone -r HEAD https://mysvnsrv.org/rep/trunk folder
 
  git log -5
 
  git log -5
 +
git status
 +
git svn info
 +
git config --list
 +
</pre>
  
 
Create a .gitignore file on the toplevel to replicate svn's ignore properties.
 
Create a .gitignore file on the toplevel to replicate svn's ignore properties.
 
  echo "folder/or/file/to/ignore" > .gitignore
 
  echo "folder/or/file/to/ignore" > .gitignore
 +
 +
Make sure to remove directories from the svn tree if there are no files left in it. This is important for a directory move to have no left-overs. As well assure that line endings are UNIX style, and git does not tinker with them (see below "git svn rebase fails" if it tinkers). An example to change the line endings for java files, and switch of warnings:
 +
git config --global svn.rmdir true
 +
git config --global core.autocrlf input
 +
git config --global core.safecrlf false
  
 
== commit ==
 
== commit ==
 
=== commit to local Git ===
 
=== commit to local Git ===
 
Git automatically tracks contents and therefor automatically detects all changes done with file browsers, programming tools etc.
 
Git automatically tracks contents and therefor automatically detects all changes done with file browsers, programming tools etc.
 +
git diff
 
  git add --all
 
  git add --all
 +
git diff --cached
 
  git commit -m "whatebber"
 
  git commit -m "whatebber"
 +
 +
If there is a warning like
 +
  warning: CRLF will be replaced by LF in bladiblu/dir/...
 +
  The file will have its original line endings in your working directory.
 +
consider converting all files to UNIX eol style, here an example for java:
 +
  find . -name *.java -exec dos2unix --d2u {} \;
 +
If not, and git svn rebase fails because of line endings (true for git <= 1.8.1) see howto's below.
  
 
=== commit to remote SVN ===
 
=== commit to remote SVN ===
Line 33: Line 53:
 
  git svn dcommit
 
  git svn dcommit
  
Things in the working copy can be reset (reverted) to what is checked in:
+
Things in the working tree can be reset (reverted) to what is checked in via "reset". A "clean" removes unknown files and directories from the working tree:
 
  git reset --hard
 
  git reset --hard
 +
git clean -d -x -n
 +
 +
Also, single files can be reset to a previous version. one caret means one version back:
 +
git checkout HEAD^ -- singlefile
 +
git commit --amend
 +
 +
 +
== basic workflow, check out, fix, check in to svn ==
 +
git svn clone -r HEAD https://mysvnsrv.org/rep
 +
... hack, hack, hack ...
 +
git add --all
 +
git commit -m "qick fix"
 +
git svn dcommit
 +
 +
 +
== workflow with quickly setting away your main work and do a quick fix ==
 +
git svn clone -r HEAD https://mysvnsrv.org/rep
 +
git checkout -b bugfix-id-123
 +
... hack, hack, hack ...
 +
git stash "main work, save it for the moment"
 +
git stash list
 +
... hack on quick fix ...
 +
git commit -m "qick fix"
 +
git svn dcommit
 +
git stash pop
 +
... continue hack, hack, hack ...
 +
 +
== workflow with local fix/feature branch ==
 +
git svn clone https://mysvnsrv.org/rep
 +
git checkout -b bugfix-id-123
 +
<hack, hack, hack>
 +
git add --all
 +
git commit -m "fixed issue 123"
 +
git checkout master
 +
git svn rebase
 +
git merge bugfix-id-123
 +
git svn dcommit
 +
 +
 +
== howto's ==
 +
 +
=== How to use local git branches with git svn ===
 +
[http://www.kernel.org/pub/software/scm/git/docs/git-svn.html git-svn(1)] allows you to use git as an interface to a Subversion repository. However, there are a number of caveats when doing this because Subversion's branching model is less powerful. [http://www.kernel.org/pub/software/scm/git/docs/git-merge.html git-merge(1)] should not be used on the branch you intend to ''git svn dcommit'' from because the merge object cannot be expressed in a useful form to the Subversion repository when committing. This essentially makes it impossible to usefully use git branches for local development - yet the branching/merging mechanism is one of the most powerful features that git provides.
 +
 +
There are two ways to get around the ''git merge'' problem and so be able to use git branches for (local) development. For the following, assume you've branched and the commit genealogy looks like:
 +
 +
<pre><nowiki>
 +
    C--E--F branch
 +
    /
 +
A--B--D master
 +
</nowiki></pre>
 +
The first merge solution is to replicate the changes you made on your branch to ''master'' using [http://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html git-cherry-pick(1)] (or alternatively [http://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html git-format-patch(1)] and [http://www.kernel.org/pub/software/scm/git/docs/git-am.html git-am(1)]). However, it can be rather laborious determining the list of required commits (C,E,F) and iteratively re-applying them to ''master'' (C', E', F').
 +
 +
<pre><nowiki>
 +
    C--E--F branch
 +
    /
 +
A--B--D--C'--E'--F' master
 +
</nowiki></pre>
 +
Whilst this does allow you to develop multiple projects simultaneously and independently, this work-around isn't much friendlier than just working directly on ''master'' in the first place.
 +
 +
The second solution takes advantage of [http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html git-rebase(1)] and [http://www.kernel.org/pub/software/scm/git/docs/git-branch.html git-branch(1)]. When you want to merge your changes back to ''master'' you rebase your branch with respect to ''master'' HEAD (i.e. what the Subversion repository looks like):
 +
 +
<pre><nowiki>
 +
git checkout <branch>
 +
git rebase master
 +
</nowiki></pre>
 +
Your branch now looks like ''master'' plus the extra changes you made on the branch:
 +
 +
<pre><nowiki>
 +
        C"--E"--F" branch
 +
      /
 +
A--B--D master
 +
</nowiki></pre>
 +
In fact, it's what you'd ideally like to ''git svn dcommit'' now (or later) but it's stuck on the wrong branch. So now we tell git that we'd like to pretend that the branching never happened and that ''branch'' is what ''master'' should really look like:
 +
 +
<pre><nowiki>
 +
git branch -M master
 +
</nowiki></pre>
 +
The -M specifies that we want to do a forced rename of the branch (forced because ''master'' already exists):
 +
 +
<pre><nowiki>
 +
A--B--D--C"--E"--F" master
 +
</nowiki></pre>
 +
Note that this destroys the development branch in the process* so this should only be done when you've finished development on the branch. However, there's nothing stopping you from re-branching again:
 +
 +
<pre><nowiki>
 +
git checkout -b <branch>
 +
</nowiki></pre>
 +
<pre><nowiki>
 +
                  o branch
 +
                  /
 +
A--B--D--C"--E"--F" master
 +
</nowiki></pre>
 +
* Technically we destroyed the old ''master'' branch but since ''branch'' can no longer be referred to by name it appears as though that is the object that was destroyed.
 +
 +
=== An Alternate Method Using `git-svn rebase` ===
 +
If you have a branch like above, you can often perform a <code><nowiki>git-svn rebase</nowiki></code> on the branch directly. Instead of rebasing to master, this rebases the branch directly onto the latest remote revision in subversion. Then you can <code><nowiki>git-svn dcommit</nowiki></code> ''in the branch''. Finally, check out <code><nowiki>master</nowiki></code> and do another <code><nowiki>git-svn rebase</nowiki></code> to bring it up to date. This will merge in the changes from the branch as well as any new changes in subversion. Note that with this method, the branch sticks around, but afterwards <code><nowiki>gitk</nowiki></code> will show that it marks the same history as <code><nowiki>master</nowiki></code> -- until you commit to it again or delete it, anyway.
 +
 +
=== git svn rebase fails, what now? ===
 +
Especially if on Windows, a "git svn rebase" might fail with a merge conflict, e.g. because of line endings (at least with git <= 1.8.1). If this happens you might want to put the changes in a dedicated branch "wip" (work in progress), reset the master onto a commit which is in svn, and then cherry pick the changes from wip onto master. Interestingly this is not sensitive to line ending style.
 +
 +
== Remote svn branches and git-svn ==
 +
=== add a branch afterwards ===
 +
To track a branch created on a non-standard location in subversion add it to git:
 +
<pre>
 +
brnch=mymodule-1.0
 +
git config --add svn-remote.${brnch}.url https://mysvnsrv.org/rep/branches/${brnch}/code
 +
git config --add svn-remote.${brnch}.fetch :refs/remotes/${brnch}
 +
git svn fetch -r HEAD ${brnch}
 +
</pre>
 +
to switch over to another branch use one of
 +
<pre>
 +
git reset --hard remotes/branch
 +
git checkout branch
 +
</pre>
 +
 +
=== clone with branches ===
  
 
== Some links ==
 
== Some links ==
 +
* [[Media:Git-svn-cheatsheet.pdf|git-svn cheatsheet]] - all important git-svn commands on a page
 +
* [[GitSvnCrashCourse]], if you know svn, and want to learn git
 +
* [http://www.kernel.org/pub/software/scm/git/docs/git-svn.html git-svn]
 +
* [[GitSvnSwitch]]
 
* git-svn homepage: http://www.kernel.org/pub/software/scm/git/docs/git-svn.html
 
* git-svn homepage: http://www.kernel.org/pub/software/scm/git/docs/git-svn.html
 
* http://trac.parrot.org/parrot/wiki/git-svn-tutorial
 
* http://trac.parrot.org/parrot/wiki/git-svn-tutorial
 
* http://maymay.net/blog/2009/02/24/how-to-use-git-svn-as-the-only-subversion-client-youll-need
 
* http://maymay.net/blog/2009/02/24/how-to-use-git-svn-as-the-only-subversion-client-youll-need
 
* Git cheat sheets: [http://zrusin.blogspot.ch/2007/09/git-cheat-sheet.html Zack Rusin's], [http://jan-krueger.net/development/git-cheat-sheet-take-two in A4 by Jan Krüger], [http://jan-krueger.net/development/git-cheat-sheet-extended-edition 2 sheets by Jan Krüger]
 
* Git cheat sheets: [http://zrusin.blogspot.ch/2007/09/git-cheat-sheet.html Zack Rusin's], [http://jan-krueger.net/development/git-cheat-sheet-take-two in A4 by Jan Krüger], [http://jan-krueger.net/development/git-cheat-sheet-extended-edition 2 sheets by Jan Krüger]
 +
* [http://en.wikibooks.org/wiki/Git/git-svn git-svn on en.wikibooks.org]
 +
* tcoffee description, including tagging, committing to a branch: http://code.google.com/p/tcoffee/wiki/SvnUsingGitClient
 +
*  [http://utsl.gen.nz/talks/git-svn/intro.html An introduction to git-svn for Subversion/SVK users and deserters] by Sam Vilain describes how to import from and work with Subversion repositories and SVK mirrors. Also describes why would one want to choose Git over Subversion.
 +
* [http://michael-prokop.at/blog/2007/12/03/git-svn-in-30-minutes/ git(-svn) in 30 minutes] on [http://michael-prokop.at/blog mikas blog], not only about git-svn.
 +
* [http://wiki.samba.org/index.php/Using_Git_for_Samba_Development Using Git for Samba Development] and [http://wiki.samba.org/index.php/Using_Git-SVN_for_Samba4_Development Using Git-SVN for Samba4 Development]
 +
 +
[[Category:GitDocumentation]] [[Category:git-svn documentation]]

Latest revision as of 14:53, 31 March 2014

This tutorial collects information for users of git as subversion client, using git-svn. As Git is distributed, commits (aka change sets) are referenced by hashes instead of svn's serial version numbers. Git tracks contents, not files or directories. Consider to use a real svn client to rename directories, as git-svn produces a lot of renames in svn, instead of one like the original. git-svn is not a good tool to convert from svn to git, see here for better options.

Contents


[edit] checkout / clone, log, configure basics

 git svn clone -r HEAD https://mysvnsrv.org/rep/trunk folder
 git log -5
 git status
 git svn info
 git config --list

Create a .gitignore file on the toplevel to replicate svn's ignore properties.

echo "folder/or/file/to/ignore" > .gitignore

Make sure to remove directories from the svn tree if there are no files left in it. This is important for a directory move to have no left-overs. As well assure that line endings are UNIX style, and git does not tinker with them (see below "git svn rebase fails" if it tinkers). An example to change the line endings for java files, and switch of warnings:

git config --global svn.rmdir true
git config --global core.autocrlf input
git config --global core.safecrlf false

[edit] commit

[edit] commit to local Git

Git automatically tracks contents and therefor automatically detects all changes done with file browsers, programming tools etc.

git diff
git add --all
git diff --cached
git commit -m "whatebber"

If there is a warning like

 warning: CRLF will be replaced by LF in bladiblu/dir/...
 The file will have its original line endings in your working directory.

consider converting all files to UNIX eol style, here an example for java:

  find . -name *.java -exec dos2unix --d2u {} \;

If not, and git svn rebase fails because of line endings (true for git <= 1.8.1) see howto's below.

[edit] commit to remote SVN

To see what is going to be committed one can choose the following options.

gitk git-svn..
gitk
git log remotes/git-svn.. --oneline
git svn dcommit --dry-run

To really commit

git svn dcommit

[edit] undo changes

Undo (backout, revert) changes and commits is done with standard git commands.

Things already committed to svn can be reverted:

git revert <hash>
git svn dcommit

Things in the working tree can be reset (reverted) to what is checked in via "reset". A "clean" removes unknown files and directories from the working tree:

git reset --hard
git clean -d -x -n

Also, single files can be reset to a previous version. one caret means one version back:

git checkout HEAD^ -- singlefile
git commit --amend


[edit] basic workflow, check out, fix, check in to svn

git svn clone -r HEAD https://mysvnsrv.org/rep
... hack, hack, hack ...
git add --all
git commit -m "qick fix"
git svn dcommit


[edit] workflow with quickly setting away your main work and do a quick fix

git svn clone -r HEAD https://mysvnsrv.org/rep
git checkout -b bugfix-id-123
... hack, hack, hack ...
git stash "main work, save it for the moment"
git stash list
... hack on quick fix ...
git commit -m "qick fix"
git svn dcommit
git stash pop
... continue hack, hack, hack ...

[edit] workflow with local fix/feature branch

git svn clone https://mysvnsrv.org/rep
git checkout -b bugfix-id-123
<hack, hack, hack>
git add --all
git commit -m "fixed issue 123"
git checkout master
git svn rebase
git merge bugfix-id-123
git svn dcommit


[edit] howto's

[edit] How to use local git branches with git svn

git-svn(1) allows you to use git as an interface to a Subversion repository. However, there are a number of caveats when doing this because Subversion's branching model is less powerful. git-merge(1) should not be used on the branch you intend to git svn dcommit from because the merge object cannot be expressed in a useful form to the Subversion repository when committing. This essentially makes it impossible to usefully use git branches for local development - yet the branching/merging mechanism is one of the most powerful features that git provides.

There are two ways to get around the git merge problem and so be able to use git branches for (local) development. For the following, assume you've branched and the commit genealogy looks like:

     C--E--F branch
    /
A--B--D master

The first merge solution is to replicate the changes you made on your branch to master using git-cherry-pick(1) (or alternatively git-format-patch(1) and git-am(1)). However, it can be rather laborious determining the list of required commits (C,E,F) and iteratively re-applying them to master (C', E', F').

     C--E--F branch
    /
A--B--D--C'--E'--F' master

Whilst this does allow you to develop multiple projects simultaneously and independently, this work-around isn't much friendlier than just working directly on master in the first place.

The second solution takes advantage of git-rebase(1) and git-branch(1). When you want to merge your changes back to master you rebase your branch with respect to master HEAD (i.e. what the Subversion repository looks like):

git checkout <branch>
git rebase master

Your branch now looks like master plus the extra changes you made on the branch:

        C"--E"--F" branch
       /
A--B--D master

In fact, it's what you'd ideally like to git svn dcommit now (or later) but it's stuck on the wrong branch. So now we tell git that we'd like to pretend that the branching never happened and that branch is what master should really look like:

git branch -M master

The -M specifies that we want to do a forced rename of the branch (forced because master already exists):

A--B--D--C"--E"--F" master

Note that this destroys the development branch in the process* so this should only be done when you've finished development on the branch. However, there's nothing stopping you from re-branching again:

git checkout -b <branch>
                   o branch
                  /
A--B--D--C"--E"--F" master
  • Technically we destroyed the old master branch but since branch can no longer be referred to by name it appears as though that is the object that was destroyed.

[edit] An Alternate Method Using `git-svn rebase`

If you have a branch like above, you can often perform a git-svn rebase on the branch directly. Instead of rebasing to master, this rebases the branch directly onto the latest remote revision in subversion. Then you can git-svn dcommit in the branch. Finally, check out master and do another git-svn rebase to bring it up to date. This will merge in the changes from the branch as well as any new changes in subversion. Note that with this method, the branch sticks around, but afterwards gitk will show that it marks the same history as master -- until you commit to it again or delete it, anyway.

[edit] git svn rebase fails, what now?

Especially if on Windows, a "git svn rebase" might fail with a merge conflict, e.g. because of line endings (at least with git <= 1.8.1). If this happens you might want to put the changes in a dedicated branch "wip" (work in progress), reset the master onto a commit which is in svn, and then cherry pick the changes from wip onto master. Interestingly this is not sensitive to line ending style.

[edit] Remote svn branches and git-svn

[edit] add a branch afterwards

To track a branch created on a non-standard location in subversion add it to git:

 brnch=mymodule-1.0
 git config --add svn-remote.${brnch}.url https://mysvnsrv.org/rep/branches/${brnch}/code
 git config --add svn-remote.${brnch}.fetch :refs/remotes/${brnch}
 git svn fetch -r HEAD ${brnch}

to switch over to another branch use one of

git reset --hard remotes/branch
git checkout branch

[edit] clone with branches

[edit] Some links

Personal tools