Log in
R. Kris Hardy Photo

R. Kris Hardy

July 2, 2011

Getting Started with Git and SVN

Filed under: Articles,Development — Tags: — Kris @ 9:32 am

Getting Started with Git and SVN

What is Git, and why would you want to use it?

Git is a distributed version control system that was written by Linus Torvalds (the developer of the Linux kernel). “Distributed” means that the entire revision history is stored on your local machine, which allows you to manage commits, rollback changes, merge branches, tag, etc., all without having to maintain a constant connection to the central svn server.

This also allows you to use very non-linear development methods, and incrementally commit changes and publish those changes on SVN in one batch once you know that everything that you’re working on works.

The other really nice part of git is that you can branch your code in-place on your local machine, meaning that you can branch the trunk and make multiple branches (and even branches of branches) to try things out and see what works best. Once you have your changes in place, you can merge the branches back together and commit them to svn.

I’ve has been using this for my development starting in May 2011, and I’ve been really happy with it, although it takes a little time to get used to. This page is working document of some of the tricks, lessons, and best practices that I’ve picked up as I’ve started to use git. (BTW, I’m so happy with git that all my personal development projects have been entirely migrated to git both on the workstation and my server).

If you have any questions, make sure to post a message below. I continue to add to this tutorial so that I have a central place to store my working knowledge of git svn.

Thanks!

Introductory Material (or reference material if you get stuck)

To start with, here is a cheatsheet of git commands, and how they relate to svn. Now, git can do a LOT more than this, but it will help you get started with understanding how git works.

For a more lengthy introduction to git, read the Git Tutorial and then the Everyday GIT with 20 commands or so page.

Typical Workflow with Git and SVN

Before you start this tutorial, if you want to also try committing to a svn server, send me an e-mail at kris@rkrishardy.com, and give me your e-mail address so that I can give you commit access. (I just ask that you be considerate with what you commit, and don’t commit anything that is not tasteful).

To get started, first, download and install Git. If you are on Windows, download Git from http://git-scm.com. If you are on a Unix/Linux variety, use your repository or package manager.

On Fedora/RedHat/CentOS:

$ sudo yum install git git-svn

On Debian/Ubuntu:

$ sudo apt-get install git-core git-svn

For FreeBSD, check out the instructions for installing packages and ports, depending on your preference.

Now, let’s use the git-svn-sandbox project at code.google.com as an example to show you how this works.

The directory that you want to clone from svn is the one with the trunk/tags/branches directories inside of it. For example, let’s clone git-svn-sandbox.


$ git svn clone https://git-svn-sandbox.googlecode.com/svn/ git-svn-sandbox -Ttrunk -bbranches -ttags --username your@emailaddress.com
This may take a while on large repositories
Checked through r...
...
Checked out HEAD:
http://code.google.com/p/git-svn-sandbox r...

This will create a git-svn-sandbox folder and clone the entire svn history into the git-svn-sandbox/.git folder. This may take some time because it needs to walk the entire svn revision tree, so grab some tea or coffee and give it a few minutes.

Once the cloning is done, you should have a local ‘master’ branch in place:


$ cd git-svn-sandbox
$ git branch
* master

The ‘*’ shows you which branch you currently have checked out. You should currently be in the “master” branch.

Now, see what remote tracking branches are available (these are on the SVN server):


$ git branch -r
tags/1.0
test
trunk

git branch is the command to use for managing local branches. Using git branch, you can create, delete, merge, etc. your local branches. (These are isolated from the SVN remote branches, and branches you create here are not automatically uploaded to the SVN server, so create and delete branches without fear).

SVN doesn’t handle conflicts smoothly, so here’s what I do. Before I start changing anything, I first create a new local branch and start working on that. If you forget to branch, that’s OK. If you get a conflict during the git svn rebase or git svn dcommit, see the “I did an git svn rebase, but I got a bunch of merge errors. What should I do?” section below.


$ git checkout -b my_branch
Switched to a new branch 'my_branch'

You have created a new branch and switched to it. This command was
shorthand for:


$ git branch my_branch
$ git checkout my_branch

Now, and and/or edit the files you need to. When you are done, take a
look at the list of files that changed.


$ git status
# On branch my_branch
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working
directory)
#
# modified: test.txt
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# abcd.123
no changes added to commit (use "git add" and/or "git commit -a")

Here, text.txt is already in the git index and has been modified but not flagged to be committed. Also, abcd.123 has been added, but is not in the git index.

To add both to the git index, use git add -A (which adds all untracked and modified files to the index).

$ git add -A

Now you can commit the files to the git branch using git commit.


$ git commit
[my_branch db1292d] Saving changes
2 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 abcd.123

When you are done developing and you want to share your code on the svn server, make sure that you have all the files checked into your development branch.


$ git status

Add and commit any changes that show up, and then checkout the master branch.


$ git checkout master
Switched to branch 'master'

If you didn’t remember to do your development in a different branch, and you made modifications in master, follow the instructions in “I did an git svn rebase, but I got a bunch of merge errors. What should I do?” if you run into any problems with the next set of steps.

Rebase your master branch with the svn server.


$ git svn rebase
...
Current branch master is up to date.

If any files had been committed to svn by other developers, you should see the changes applied in the output of git svn rebase.

Merge in the changes that you want to commit to svn.


$ git merge temp
Updating 3877696..f68e10c
Fast-forward
test.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 test.txt

If you see any conflicts in the output, you can find the conflicts by using git status.

$ git status

If you want to diff the conflicts, use git diff.

$ git diff

Once the conflicts have been resolved, make sure that all the changes have been committed to master. Then commit the changes to svn using git svn dcommit.


$ git commit
$ git svn dcommit --username your@emailaddress.com
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...
A test.txt
Committed r4
A test.txt
r4 = 4c55148ecefac8b83b626fa568b2bc1f99ea990e (refs/remotes/trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

If git svn dcommit failed with a message stating “Authorization failed: …”, I need to give you commit access to the repository. Please send me an e-mail at kris@rkrishardy.com, and give me your e-mail address so that I can give you commit access. (I just ask that you be considerate with what you commit, and don’t commit anything that is not tasteful).

If you got the “Committed r…” line, congratulations! Your changes have been published to the svn server!

If you want to continue working on your local development branch, check it back out and rebase it to bring it up to date with the master.


$ git checkout my_branch
$ git rebase master
First, rewinding head to replay your work on top of it...

When you are completely done with your branch, you can delete it by checking out a different branch and using git branch -d.


$ git checkout master
$ git branch -d my_branch
Deleted branch my_branch (was 15971cb).

Congratulations. You now have the basic workflow down. If you run into problems, checkout out the “Troubleshooting” section below, or take a look at the Git documentation at Git SVN Cheatsheet, the
Git Tutorial, the Everyday GIT with 20 commands or so page, or the extensive Git Users Manual.

Troubleshooting

I did a git svn rebase, but I got a bunch of merge errors. What should I do?

Before you do anything, revert the rebase by typing:


$ git rebase --abort

Now, make a backup of your current master by branching it.


$ git branch temp

Use git log to figure out which commit was the last one that was sync’d with svn. Here is an example of the output:


$ git log
commit 4ebf8122c5b18ab16167268b1791fa49996e56cc
Author: Kris Hardy
Date: Sat Jul 2 10:01:55 2011 -0400

Modified test.txt

commit ec8a9e15a30c01c7ad7b83d6cb8cde39e1c6a650
Author: hardyrk@gmail.com
Date: Sat Jul 2 13:58:02 2011 +0000

 

Adding initial files

git-svn-id: https://git-svn-sandbox.googlecode.com/svn/trunk@2 fb457a7e-32b5

 

commit 96acefc8a443a02568453c7a504064ffc6d8428e
Author: (no author) <(no author)@fb457a7e-32b5-5db0-b168-d315aa6739ac>
Date: Sat Jul 2 13:12:00 2011 +0000

Initial directory structure.

 

 

 

 

git-svn-id: https://git-svn-sandbox.googlecode.com/svn/trunk@1 fb457a7e-32b5

Look for the latest git-svn-id to find the latest commit. In this example, it
was commit ec8a9e15a30c01c7ad7b83d6cb8cde39e1c6a650.

You only have to use the first few characters of the commit id, so we’ll
use ec8a9 as a short-hand for the full commit string.

Now, reset the master branch to the last version that was sync’d with
SVN. NOTE: This command will erase commits that occurred after the
commit, so make sure you backed up your master branch (using git branch)!!!.


$ git reset --hard ec8a9
HEAD is now at ec8a9

Now, you are safe to rebase master with the svn trunk using git svn rebase.

$ git svn rebase
...
Current branch master is up to date.

If any files had been committed to svn by other developers, you should see the changes applied in the output of git svn rebase.

Merge in the changes that you want to commit to svn.


$ git merge temp
Updating ec8a9..4ebf8
Fast-forward
test.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 test.txt

If you see any conflicts in the output, you can find the conflicts by using git status.


$ git status

If you want to diff the conflicts, use git diff.


$ git diff

Once the conflicts have been resolved, make sure that all the changes have been committed to master. Then commit the changes to svn using git svn dcommit.


$ git commit
$ git svn dcommit --username your@emailaddress.com
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...
A test.txt
Committed r4
A test.txt
r4 = 4c55148ecefac8b83b626fa568b2bc1f99ea990e (refs/remotes/trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

I checked out an svn branch (or tag), and how svn dcommit in master pushes the changes to the svn branch!

When checking out a remote branch or tag, master sometimes stops tracking the svn trunk, and instead starts tracking the svn branch or tag. To fix this:

  1. Check the git master branch back out
  2. Back up any changes
  3. Do a hard reset, setting the svn trunk as the remote tracking branch
  4. Reapply the backed up changes


$ git checkout master
$ git branch temp
$ git reset --hard remotes/trunk
HEAD is now at ...
$ git svn dcommit -n
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...
$ git merge temp
Updating ...
$ git branch -d temp
Deleted branch temp (was ...
$ git svn dcommit
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk
...

Adapted from StackOverflow: How do I make git-svn use a particular svn branch as the remote repository?

Stupid Git-SVN tricks

I want to ignore files from git (just like setting ‘svn:ignore’)

To ignore files from git, add the filename or filename pattern to a .gitignore file in the folder that the file is in, or in one of the folder’s ancestors if it is a global ignore (such as ignoring *.o or *~ files, for example).


$ touch .gitignore
$ echo *.o >> .gitignore
$ git add .gitignore
$ git commit -m "Ignoring *.o files"

How do I create a tag in SVN?

Use git svn tag.


$ git svn tag 1.0
Copying https://git-svn-sandbox.googlecode.com/svn/trunk at r4 to https://git-svn-sandbox.googlecode.com/svn/tags/1.0...
Found possible branch point: https://git-svn-sandbox.googlecode.com/svn/trunk => https://git-svn-sandbox.googlecode.com/svn/tags/1.0, 4
Found branch parent: (refs/remotes/tags/1.0) a029adfba661303ad73be48fcbb92372fba9a9f1
Following parent with do_switch
Successfully followed parent
r5 = 974647bc0548d3d21c67d7f6fe2904da2f02a846 (refs/remotes/tags/1.0)
$ git branch -r
tags/1.0
trunk

If you want to check to make sure that master is still tracking the svn trunk, use git svn dcommit -n.


$ git svn dcommit -n
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...

How do I create a branch in SVN?

Use git svn branch.


$ git svn branch temp
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...
$ git svn branch temp
Copying https://git-svn-sandbox.googlecode.com/svn/trunk at r4 to https://git-svn-sandbox.googlecode.com/svn/branches/temp...
Found possible branch point: https://git-svn-sandbox.googlecode.com/svn/trunk => https://git-svn-sandbox.googlecode.com/svn/branches/temp, 4
Found branch parent: (refs/remotes/temp) a029adfba661303ad73be48fcbb92372fba9a9f1
Following parent with do_switch
Successfully followed parent
r6 = 4c0195271d0d586f2facd2707a83653844fec3a2 (refs/remotes/temp)
$ git branch -r
tags/1.0
temp
trunk

If you want to check to make sure that master is still tracking the svn trunk, use git svn dcommit -n.


$ git svn dcommit -n
Committing to https://git-svn-sandbox.googlecode.com/svn/trunk ...

How do I checkout/track a remote branch or tag from SVN, and manage the files using Git?

You can create a git branch, and have it track the remote svn branch using git branch. The git branch will now be synchronized with the svn tag or branch.


$ git branch local/tags/1.0 tags/1.0
$ git branch
local/tags/1.0
* master
$ git branch -r
tags/1.0
temp
trunk
$ git checkout local/tags/1.0
Switched to branch 'local/tags/1.0'
$ git svn dcommit -n
Committing to https://git-svn-sandbox.googlecode.com/svn/tags/1.0 ...

My branches are forks of the svn trunk. How can I keep the forks up to date without the conflicts caused by git merge?

See this page for a great walkthrough (hint, use git rebase –onto):

Maintaining a Fork With Git

Technorati Tags:

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment


Powered by WordPress