How to use Git

Here you will find details on how to use git for Foswiki development. You are assumed to know what git is, and what it’s for, and you are expected to know what subversion is, and how to use it, as well.

General git tricks have been put into GitCookbook so that this page doesn’t grow beyond reason.

Some more interesting links:

Google Tech Talk: Linus Torvalds on git

Google Tech Talk: Randal Schwartz on git

git for Foswiki Developers


As Foswiki sources are stored in Subversion, one needs to use git-svn to deal with it.

git svn is a simple conduit for changesets between Subversion and git. It provides a bidirectional flow of changes between a Subversion and a git repository. git svn can track a standard Subversion repository, following the common “trunk/branches/tags” layout, with the –stdlayout option. It can also follow branches and tags in any layout with the -T/-t/-b options (see options to init below, and also the clone command). Once tracking a Subversion repository (with any of the above methods), the git repository can be updated from Subversion by the fetch command and Subversion updated from git by the dcommit command.

The git-svn manual gives out a lot of information, but you might also find the following resources useful:

Git used to be shipped with all its command-set (about 132 tools) as git-command. As this was highly criticized, it now accepts both syntaxes. For all git commands, you can either write them:

git command options


git-command options

The latter is discouraged, but is there for backward compatibility.

Also, please note that all these commands have their help system, which you can get using:

git help command

git-svn or git only?

One thing that might be surprising and scary at first is that for some commands, you have to use git svn command and for some others, only git command.

Here is a list of the git-svn commands you might use, and why:

  • clone (runs init and fetch): initial creation of your local git repository
  • init: Initialize a git repository with Subversion meta-data. You’d better use clone unless you really know what you’re doing.
  • rebase (runs fetch before rebase): Get the latest changes from Subversion,
  • fetch: get latest changes from Subversion. You’d better use rebase, unless you really know what you’re doing.
  • dcommit: Commit your local modifications back to Subversion
  • log: Supports Subversion revision numbers, which is why you might need this instead of its raw git log counterpart.
  • blame: Displays it just like svn blame did. Use this when you need the Subversion revision numbers, otherwise use git blame
  • find-rev: Maps git tree hashes to Subversion revision numbers, and vice-versa, depending what you provide it with (rXXX or a hash)
  • set-tree: Don’t use that. If you do, you should know what it does, so I won’t tell you.
  • create-ignore: Builds your .gitignore file based on the svn:ignore properties (recursive)
  • show-ignore: Show the svn:ignore properties (recursive)
  • commit-diff: Like set-tree
  • info: Same as svn info, or almost.
  • proplist: Same as svn proplist
  • propget: Gets the Subversion property for the file
  • show-externals: Show the subversion externals (whatever that is)

So basically, all you should ever use are:

  • clone
  • rebase
  • dcommit

And eventually, if needed:

  • find-rev
  • log
  • blame
  • info

Initial checkout

For now, there is no officially distributed and supported git repository for Foswiki. OlivierRaginel built on WillNorris‘ initial import on github? , and is now pushing Subversion changes to foswiki on github and to foswiki on gitorious every 15 minutes from the Subversion server. (Will try to make it a subversion post-commit hook soonish).

There are basically 3 ways to get a working git tree interfaced with the subversion one:

  1. Git clone with full history – Quick, uses roughly 200 MB of bandwidth
  2. Git clone without history
  3. Giv svn clone

Once this is done, you may start using git!

Git clone + svn

First, you need to clone a git repository, so you can use either github or gitorious

git clone git://

This will download around 200 MB of data, so your mileage may vary. On my very fast internet connection, it took around a minute to complete.

Then, you need to add the git-svn pointers, and we can use git svn init for that (this will more or less simply modify your .git/config):

cd foswiki && git svn init -s

Then, you need to restore the subversion references with the git ones, so the fetch won’t get it all again:

git update-ref refs/remotes/trunk             origin/master 
git update-ref refs/remotes/Release01x00      origin/release
git update-ref refs/remotes/Release01x01      origin/Release01x01
git update-ref refs/remotes/       origin/foswiki
git update-ref refs/remotes/scratch           origin/scratch 
git update-ref refs/remotes/Release04x02      origin/Release04x02
git update-ref refs/remotes/TWikiRelease04x02 origin/oldRelease04x02
git update-ref refs/remotes/Release           origin/oldRelease

Finally, you fetch everything that’s different:

git svn fetch

In theory, this should be pretty minimal. Turns out at least one commit (revision 3) causes issue, so it’s not as minimal as I would like it to be, but I’m working on it.

So, if you have the error:

Last fetched revision of refs/remotes/TWikiRelease04x02 was r3, but we are about to fetch: r3!

, this is because your branch points to something which git thinks is different from Subversion’s r3. To fix that, simply delete your.git/refs/remotes/TWikiRelease04x02 and try again to fetch:

rm -f .git/refs/remotes/TWikiRelease04x02

UPDATE: (2010-12-17) Today I (OlivierRaginel) had the same error on my git-svn checkout which had been working since day 1. I took a more drastic approach:

git update-ref refs/remotes/TWikiRelease04x02 facceb0522b9016ff134cfc11626d9c664f529de 2fc6569228230096fb3d055c43f1ae08357a4069

Basically, it does more or less the same as:

$ grep TWikiRelease04x02 .git/packed-refs
2fc6569228230096fb3d055c43f1ae08357a4069 refs/remotes/TWikiRelease04x02
$ perl -i.bak -nle 'print unless /TWikiRelease04x02/' .git/packed-refs
$ git svn fetch
$ grep TWikiRelease04x02 .git/packed-refs
facceb0522b9016ff134cfc11626d9c664f529de refs/remotes/TWikiRelease04x02

This removed the bogus cached version, and put back the proper one which is facceb0522b9016ff134cfc11626d9c664f529de. In case anything goes wrong, the.git/packed-refs has been saved in .git/packed-refs.back if you used the latter. If the SHA1 don’t match, the former will refuse to update anything, so it should be pretty safe.

Summary of what I did to test it out:

$ git clone git://
Initialized empty Git repository in /export/03a/babar/foswiki/.git/
remote: Counting objects: 150965, done.
remote: Compressing objects: 100% (61219/61219), done.
remote: Total 150965 (delta 69607), reused 150743 (delta 69437)
Receiving objects: 100% (150965/150965), 187.55 MiB | 14729 KiB/s, done.
Resolving deltas: 100% (69607/69607), done.
Checking out files: 100% (30662/30662), done.
$ cd foswiki/
$ git svn init -s
$ git update-ref refs/remotes/trunk             origin/master 
$ git update-ref refs/remotes/Release01x00      origin/release
$ git update-ref refs/remotes/       origin/foswiki
$ git update-ref refs/remotes/scratch           origin/scratch 
$ git update-ref refs/remotes/Release04x02      origin/Release04x02
$ git update-ref refs/remotes/TWikiRelease04x02 origin/oldRelease04x02
$ git update-ref refs/remotes/Release           origin/oldRelease
$ git svn fetch

The fetch gave some output…

Git clone without history

If you want to use git, but do not care about history, or want to fetch it when you can (like when your quota allows it), you can use:

git svn clone -r 7500 -s

This way, you will get only the history starting at revision 7500. You may then use svn fetch -r … to fill in the blanks, but you will end up downloading as much as the method below, whereas the one above should be much faster.

Git svn clone

BEWARE: This cloning process is slow, very resource-intensive on the subversion server, as it checks out every single commit since the beginning. So please try to do this at some non-busy times, such as during daytime in Australia, roughly.

To clone the foswiki repository, issue:

git svn clone -s

The -s option tells git-svn to use the standard layout of subversion, thus branches are in branches/ and tags are in tags/

Working with git

Below I’ll explain how I work daily with git, especially how I deal with tasks.

Create a working branch

One great thing with git is that it’s made for branching and merging. Thus it encourages you to create branches, and often you’d wish you would have made a branch instead of starting to hack around (don’t worry, you can create a branch with your latest changes, git is that flexible).

So, let’s say we want to deal with Foswikitask:Item666, we thus create a branch called Item666 (you might be a bit more verbose, but I usually know what I’m working on, or I just look up the item):

Ensure we have all the latest changes (quick way):

git svn rebase
git checkout -b Item666

This assumes you’re on a working copy of trunk.

First ensure we have all latest changes, and then branch trunk (detailed way):

git svn fetch
git checkout trunk
git branch Item666
git checkout Item666

The first 2 commands should be combined into one using git svn rebase The last 2 commands can be combined into one using git checkout -b Item666 trunk

Creating a branch with the item number you’re working on is very useful, because Foswiki subversion repository requires your commit messages to have a working Item number, otherwise they’re rejected. If you create a branch with it, you can easily add it in front of all your commit messages. You could even script it if you want.

Work on it

Now you’ve got your own playground, thus you may work on it.

  • Edit files, using your favorite text editor (don’t forget to run perltidy -b on perl code)
  • Commit them, using git commit -a to commit everything, or git commit path/to/file to commit a single file
  • roll-back them, using git revert ...
  • move files or directories around, using git svn mv
  • diff your local files with the latest committed version, using git diff

Remember: EVERYTHING you’ll do here will only be LOCAL. NOBODY will ever see anything unless you “push” your changes afterwards. Thus you may try things out, test things, without fearing any shame. I insist because many people often are afraid to commit things because they fear what others might think of their commits, or that their commits might break some things. Here, you’ll only break your own local installation, in your own local branch. If you never manage to finish your work, or give up, you can delete the branch and forget about it. Or you can push it to some other git repository for others to try it out.

Get the latest changes from subversion

Often the branch you merged from changes while your working on your local branch. And one day, you want to get the latest changes that occur in that branch, but in your own branch.

To do so, you might do it manually (using git cherry-pick, git squash, etc...), or you can use git rebase -i trunk *Note:* This doesn’t get changes from svn. You need to change to master, and do a git svn rebase

BIG FAT WARNING Never use rebase on a branch that other people have retrieved. As rebase rewrites history, they won’t be able to follow it afterwards.

But in our case, it’s just us who are working on this local branch, so it’s fine.

What rebase will do, is simply roll back all your changes since the branch point, then go to the branch you tell it to go, and apply them back.

There are a few links which explain this pretty well, especially and

So, if you’re on your Item666 branch, and want to get all what happend in trunk (so that you can safely publish your changes back to subversion), simply issue:

git rebase -i trunk

And you’ll see all the changes you made on your branch.

What rebase will do it:

  • Come up with a list of commit-id and their commit message, and ask you what you want to do with them
  • If you want more information about a commit, as sometimes the id + message isn’t enough, you may view the actual diff using: git show commit-id

The great thing about this is that you can edit everything.

  • To pick a commit, put pick at the beginning of its line.
  • To squash a commit (merge a commit with another one), pick (see above) the first commit, and then put the second commit just below it, and put squash at the beginning of its line.
  • To ignore a commit, simply remove its line. It won’t be lost, you can always cherry-pick it later.
  • To amend a commit (edit the commit message), put edit at the beginning of its line. Please note that squashing will automatically trigger amending, and amends implies pick.
  • To re-order commits, simply re-order the lines

When you save and exits your editor, git will start doing what you’ve told it to do. If you used edit, it will stop and wait for you to do what you want (using git add orgit revert or whatever). Then, continue rebasing with: git rebase --continue

You may abort rebasing with git rebase --abort, as sometimes it’s not doing what you want, and you want to start it all over again.

What you’ll be rebasing here is what you will commit back to subversion in the next paragraph, so be careful of what you do.

As rebasing is just like any other merge, you might encounter some merge issues. In such case, resolve the merge manually (edit the file, look for the

<<<<< ==== >>>>>

, and resolve the conflict), and use

git add path/to/file

to mark the conflict as solved. Then, resume the merge with:

git rebase --continue


If you want to skip a commit, you should have removed it above. But you can still do it here, using

git rebase --skip

Publish back your changes

As with any branching, one day you’ll eventually want to merge them back. To do so, it’s safer to first merge locally using git rebase (see above), then, once you’re happy with your merge, your commit messages, your commit messages, etc… you may publish them back.

To do so, simple use:

git svn dcommit

This will commit all the changes you’ve done to the remote branch you’ve just rebased, on the remote subversion repository. It should show you the mapping between subversion revision numbers and your local git commit ids.

git svn dcommit --edit

This will do the same as above, but allows you to alter the commit messages (by default the commit message you recorded in your local commit would be used).

If this is successful, it should leave you in the new trunk, with your changes being appended. If some other people committed things between your latest fetch and your dcommit, the dcommit will download these changes too.

And you’re done!

Delete your branch

Now that you’ve fixed Foswikitask:Item666, you should edit the topic and delete your local branch (it’s been merged into another remote branch anyway, so you don’t need it anymore).

If you are in the Item666 branch, you have to get out of that branch before you can delete it – use git checkout [someother branch - like master] — Sven

To do so, use:

git branch -d Item666

Display what a commit was

git has many wonderful features. One is git show, which will show you what the SHA1 points to. It’s very useful in combination of git cherry-pick (to pick one specific commit or group of commits), or git rebase to exactly know what a commit was doing.

git show 4389hfa

Find who broke a feature

Let’s imagine you have some unit tests that have been failing for some time, and nobody had time to really check what broke them. There is nothing obvious. git bisect comes to the rescue:

  1. Start the dichotomization: git bisect start
  2. Check out one version you know fails, test it. If it fails, tell git:
    git bisect bad
    • git reset --hard

      TODO: brutal – you will lose any changes

    • cd core ; ./ -A developer ; cd test/unit ; ../bin/ -clean Fn_SEARCH::verify_date_param_PurePerlSearch ; cd ../../../
      • (Or test from web. Determine if the checkout actually fails)
    • git bisect bad

      (This tells git that the current checkout is bad)

  3. Check out an older version, can be very old, but it has to work. Test it. If it works, tell git: git bisect good. If it fails, go back further to find a release that works.
    • git checkout -f lastok

      (lastok is a release identifier, like d05a118a2d2e3387391fb8b3e6616d858910d40a) TODO: Sven labeled a known good rev using gitk using the last successful build from

    • cd core ; ./ -A developer ; cd test/unit ; ../bin/ -clean Fn_SEARCH::verify_date_param_PurePerlSearch ; cd ../../../
      • or re-run web test
    • git bisect good
  4. git will then automatically choose which revision you ought to test. Test it, and report whether it’s good or bad. Each time you’ll report, git will find a new revision to test, until there will be only one.
    • cd core ; ./ -A developer ; cd test/unit ; ../bin/ -clean Fn_SEARCH::verify_date_param_PurePerlSearch ; cd ../../../
    • git bisect goodORbad
  5. Eventually, you’ll find the commit that broke everything, so now you may blame someone and send him a VirtualBear? !
  6. Be sure to issue a git bisect reset to clear the bisect. If later on you are unable to run bisect and get fatal error: invalid reference, remove the BISECT_ files from your .git directory to recover.

Developers known to be using git

Please add yourself to the list, if you tried it and stuck to it

Developer Since
OlivierRaginel Day 1 of Foswiki, for TWiki, a few months before
SeanMcCarthy ~ July 2008
WolfgangDenk ~ June 2005
GilmarSantosJr ~ Jan 2009
RaulFRodriguez ~ Feb 2010
AntonioTerceiro ~ Sep 2008
PaulHarvey ~ May 2010
AndrewJones June 2010
DrakeDiedrich ~ Jan 2010
GeorgeClark 27 Jun 2010
SvenDowideit 1 Oct 2010
JoenioCosta ~ Jan 2010


OlivierRaginel wrote this on 10 Dec 2008 after having wanted to teach others how to use git for Foswiki. I (OlivierRaginel) am not a very experienced git user, but at least I’m a very happy one. I wouldn’t be able to go back to CVS or Subversion now that I’ve experienced the power of git. If you have any question about it, or need help doing something, let me know (check on IRC if I’m around)

Current git branch name in your shell prompt

Buried in a reply to one of the blog posts linked to in this topic talking about git svn is a .bashrc snippet to put the active branch name of the current directory into the shell prompt. This is what I’ve got:

Error: no such plugin chili
# Put Git branch name it shell prompt
parse_git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* (.*)/(1)/'
PS1="${debian_chroot:+($debian_chroot)}[33[01;32m]u@h[33[00m]:[33[01;34m]w[33[00m] $gitbranch$ "

Which works for me on Ubuntu karmic (10.04), and looks like this:

csirac@kosh:/usr/local/src/ (master)$ git branch Item9007
csirac@kosh:/usr/local/src/ (master)$ git checkout Item9007
Switched to branch 'Item9007'
csirac@kosh:/usr/local/src/ (Item9007)$

Reverting the working copy

git reset --hard


GeorgeClark added these comments after not really following all of the above. Thanks to Babar and pharvey, who spent quite a bit of time on irc helping be understand.

The default branch from git is the master checkout. Files modified – but not committed to any branch are visible to all branches. So pseudo-install into coredirectory as done when running from SVN, and the results will be shared across all branches.

  • git checkout -b Item666 – creates a new branch.
  • Edit files. If they are not committed to any branch the modifications will appear across all branches.
    • This is not the right way to do it! The correct way is to pseudo-install -u before switching branches.
    • Files that you want to keep can be committed without an Itemxxxxx” in the comment, and set aside with the git stash command
  • If you switch back to master – git checkout master you will get a report of modified files and the modifications will appear in the master branch (testing)$ git checkout master
M       core/
Switched to branch 'master'
  • Commit the changed file to the testing branch by switching back to testing git checkout testing and then commit the change to the git branch – in the above example: git commit
  • git diff master..testing will show the committed differences between git branches. It doesn’t compare to SVN, It compares between your local git branches.
  • Continue testing, working and committing. to pull the latest SVN changes, switch back to master git checkout master and then git svn rebase and the changes will be applied to your master branch.
  • To get the latest svn changes into your testing branch, switch to testing git checkout testing and then rebase. git rebase will roll back your local commits, apply the changes to master, and then replay your local changes. This is your opportunity to rewrite history
    • git rebase -i master will prompt you with a list of your local changes prior to the replay. This is your opportunity to combine multiple commits. The help message is:
      # Commands:
      #  p, pick = use commit
      #  r, reword = use commit, but edit the commit message
      #  e, edit = use commit, but stop for amending
      #  s, squash = use commit, but meld into previous commit
      #  f, fixup = like "squash", but discard this commit's log message
      # If you remove a line here THAT COMMIT WILL BE LOST.
  • Once work is completed, to upload to svn, issue git svn dcommit. This will send each git commit and commit amendment to svn as an individual commit. Use the git rebase -i master command to merge together git commits, update comments, and drop undesired commits (which will be lost forever )

Accessing the release branch

More hints thanks to Babar on irc. The initial git svn clone pulls down all of the svn repository into git, but the branches are not obvious. git branch only lists the master and local branches. In order to see other branches use: git branch -a

myhost:/var/www/foswiki/trunk (release)$ git branch -a

If the branch you want is new – and not listed here, first issue git svn fetch to pull down any new branches.

  • Issue a git checkout for the remote release branch
myhost:/var/www/foswiki/trunk (master)$ git checkout remotes/Release01x00        
Note: checking out 'remotes/Release01x00'.
  • Checkout to create a new branch
myhostl:/var/www/foswiki/trunk ((no branch))$ git checkout -b release
Switched to a new branch 'release'

Accessing extensions from the release branch.

Hints from Babar and Gilmar. You will discover that in a release branch, there are no extensions at the root level other than the core extensions. These can be individually checked out into the release branch – and will show up as added files.

dev@myhost: /var/www/foswiki/trunk (master) git checkout release
Checking out files: 100% (30950/30950), done.
Switched to branch 'release'
dev@myhost: /var/www/foswiki/trunk (release)$ git checkout master ControlWikiWordPlugin
dev@myhost: /var/www/foswiki/trunk (release)$ git status
# On branch release
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#       new file:   ControlWikiWordPlugin/data/System/ControlWikiWordPlugin.txt
  • Caution: The plugin has been added to the branch and would be committed with your changes if you use commit -a
  • To clean up the checkout, git clean does not remove the added files. reset to HEAD instead.
dev@myhost: /var/www/foswiki/trunk (release)$ git reset HEAD
dev@myhost: /var/www/foswiki/trunk (release)$ git clean -f

Creating a permanent clone of a branch.

Another hint from Babar

Sometimes it’s useful to have a checkout of a branch so that a web server can remain pseudo-installed for comparison purposes.

If your git trunk checkout is located at /var/www/foswiki/trunk Now you want the release branch at /var/www/foswiki/release

  • Change to the /var/www/foswiki directory
  • Issue git clone /var/www/foswiki/trunk release
    • This will create the /var/www/foswiki/release directory with hard links to the .git files in /var/www/foswiki/trunk/
  • cd /var/www/foswiki/release && git checkout remotes/Release01x00 && git checkout -b release

This is a way to have both a release and a trunk checkout, with full history, but only use the disk space of the checkouts

If the main git tree has been updated using git svn rebase, sync up the release checkout with git pull Note that it’s not sufficient to do a git svn fetch on the main tree followed by the pull on the clone. You need to checkout the release branch and issue the git svn rebase before issuing the git pull on the cloned branch.


Git submodules in Subversion

As of Foswikirev:7120 (so 7th of April 2010), SvenDowideit added .git directory information to subversion. Depending on your version of git, this might cause havoc with git-svn, therefore, you have to tell git to ignore these paths, otherwise it will fail with:

Thanks Micha to put the error message here, I do not have it anymore

So, to fix this:

  • Use git config svn-remote.svn.ignore-paths 'trunk/WidgetsSkin/pub/System/WidgetsSkin/CMR_themes/.git:trunk/WidgetsSkin/pub/System/WidgetsSkin/CMR_themes/.git/*' to tell git to ignore this path
    fetch again using git svn fetch or git svn rebase

I had issues with git version which is the one on Debian Lenny, but it worked fine with the very same repository and config (rsync’d it over and back) on an Ubuntu Karmic, which has

— OlivierRaginel – 16 Apr 2010

Interrupted git svn clone

On my laptop, it took around 2.5 hours in total over 6MBit DSL. At one point it went into hibernation and the clone operation was interrupted.

To resume the clone, simply do git svn fetch

— PaulHarvey – 22 May 2010

The Larry vs the git rebase merge article has some valuable advice. A few times now I’ve been unable to resolve merge conflict on a heavy local branch when doing git svn rebase. Although I believe I have resolved the files, and done git add conflict/filegit rebase --continue will keep complaining that “You must edit all merge conflicts and then mark them as resolved using git add”.

This piece of text from the article was invaluable, unfortunately I only discovered after I wasted time finding out for myself:

  • If it complains about “did you forget to call ‘git add’?”, then evidently your edit turned the conflict into a no-op change. Do a “git rebase –skip” to skip it. (Very weird, but true.)

— PaulHarvey – 24 Aug 2010

Error: [some file] needs update

update-index --refresh:  command returned error: 1

There are a couple of files that are “shipped” but are also modified as part of a normal installation. It’s annoying to have git constantly complain that the file is modified and needs to be committed before permitting git svn rebase, etc. Use the git update-index command to tell git to forget about the modifications

git update-index --assume-unchanged core/data/Main/SitePreferences.txt
git update-index --assume-unchanged TopicUserMappingContrib? /data/Main/AdminGroup.txt

Don’t do this however if you intend to commit the changes upstream. Certain operations will reset this and the file will again appear modified.

— GeorgeClark – 09 Sep 2010

When git svn dcommit fails because svn commit hook rejected it

Eg. due to the new perltidy requirement

So I tried to dcommit, and it was rejected because I forgot to perltidy. This resulted in

A repository hook failed: Commit blocked by pre-commit hook (exit code 1)
trunk/WysiwygPlugin/lib/Foswiki/Plugins/ is not tidy; cannot check in:

So I did perltidy, and made another commit.

Now I have two commits ahead of master.

Then, I did git rebase -i master

I was presented with this in my editor:

pick 44f0399 Item8032: Implement new _INIT_UNKNOWN browser cfg
pick 5769307 Item8032: perltidy

Then I squashed the perltidy commit, so that svn only sees a single perltidy’d commit

pick 44f0399 Item8032: Implement new _INIT_UNKNOWN browser cfg
squash 5769307 Item8032: perltidy

After saving, my editor showed me the commit message to use, and I deleted the extraneous comment lines which git helpfully introduces to tell you what’s going on.

Then I was able to git svn dcommit

— PaulHarvey – 18 Jun 2012 – 09:32

  • .gitignore: My ~/.gitignore file for use with foswiki
  •    git config --global color.interactive always
       git config --global color.ui true
Facebook Comments