Difference between revisions of "Git"
(First part of complete rewrite for Github repository.) |
(Instructions to committers) |
||
Line 16: | Line 16: | ||
git clone git://github.com/Gnucash/gnucash.git | git clone git://github.com/Gnucash/gnucash.git | ||
+ | |||
+ | Note that the default branch is <tt>trunk</tt>, not <tt>master</tt> which is normal for git. If that bothers you, just make a tracking branch named master: | ||
+ | |||
+ | git branch -t master refs/heads/trunk | ||
When you have patches, use | When you have patches, use | ||
Line 24: | Line 28: | ||
If you have a Github account, you can fork Gnucash from within Github and clone your forked repository. This allows you to publish your fork and allows Gnucash developers to pull your changes. Please '''don't''' use the Github "pull request" mechanism; we can't work directly in the Github repository because it would break synchronization with subversion. | If you have a Github account, you can fork Gnucash from within Github and clone your forked repository. This allows you to publish your fork and allows Gnucash developers to pull your changes. Please '''don't''' use the Github "pull request" mechanism; we can't work directly in the Github repository because it would break synchronization with subversion. | ||
+ | |||
+ | === Committers === | ||
+ | ==== Set up ==== | ||
+ | Committers start by cloning the repository the same way. Since changes need to be tagged with the subversion revision, no-one should push to the Git repository; a good way to make sure that this doesn't happen by mistake is to use the same read-only URI given above for non-committers. Alternatively, fork the Gnucash repository to your Github account and clone that (use the read-write URI in that case). | ||
+ | |||
+ | Next download [https://github.com/Gnucash/git-helper-scripts/blob/master/git-update git-update], a shell script to pull changes from github and fixup the branch references for git svn. Put it somewhere on your path. | ||
+ | |||
+ | Change directory to your new local repository and run | ||
+ | |||
+ | git svn init --stdlayout svn+ssh://you@svn.gnucash.org/repo/gnucash | ||
+ | git-update | ||
+ | |||
+ | That's it. Always use <tt>git-update</tt> instead of git pull. If you forget and try to use git svn, you'll get errors because the refs that <tt>git svn</tt> can see won't match the ones in head. If you forget and run <tt>git pull</tt> by mistake, no big deal, just run <tt>git-update</tt> and everything will be fixed up. | ||
+ | |||
+ | ==== Committing ==== | ||
+ | |||
+ | git svn dcommit | ||
+ | |||
+ | Will commit your changes back to the subversion repository. | ||
+ | |||
+ | ==== Branching and Merging ==== | ||
+ | |||
+ | This is the whole point of the exercise, right? In order to not make a mess in the subversion repository, we have to be careful to keep our Git branches in Git and not bleed them into subversion by mistake. Once a branch is created in Subversion, it can be <tt>merge</tt>d exactly once back into trunk (or its parent subversion branch), but it can be <tt>rebase</tt>d or <tt>cherry-picked</tt> as much as you like. | ||
+ | |||
+ | What's the difference? When Git <tt>merge</tt>s, it creates a new reference with more than one parent. It knows when assembling a working copy how to follow those multiple parents and apply their changes in order to produce the target version. A <tt>rebase</tt> on the other hand patches the target branch for each revision in the supplying branch, creating a new set of references. <tt>Cherry-pick</tt> does the same as <tt>rebase</tt> except that it only applies selected revisions. | ||
+ | |||
+ | Subversion doesn't understand this "parent" thing, so when you <tt>dcommit</tt> a merge revision, git svn basically rebases the merge into subversion. That's fine, but if you have more than one merge between branches (especially if they go in both directions, which is pretty common in Git), git svn will get confused, either when creating the commits into svn or when extracting them to update Github. By doing the <tt>rebase</tt> yourself, git remains in control of the process and can keep the revision stream to subversion nice and linear. | ||
+ | |||
+ | ==== Collaboration ==== | ||
+ | |||
+ | So Subversion can't see our Git branches. What do we do if several developers need to work together on a feature? | ||
+ | |||
+ | There are several ways to go about it: You can pass patches between you over email, chat, or carrier pigeon; Git is designed to handle that easily (except for carrier pigeon transport, as that requires retyping the patch, which is a pain). You can arrange for all of your repositories to be available on the net, and <tt>git pull</tt> amongst yourselves. Or you can use one of the public repositories like Github and Gitorious to manage your changes. |
Revision as of 22:46, 8 March 2011
Contents
Git and Gnucash
What is Git?
Git is a distributed version control system originally developed by Linus Torvalds for managing Linux source code without requiring a central server. It is also the primary VCS used by the Gnome and Free Desktop projects. You can get the latest version for your system and read a rich variety of online documentation at Git's Home.
What has that to do with Gnucash?
Some of Gnucash's primary developers are experimenting with using Git to take advantage of its branching and merging facilities, which are much richer than those provided by Subversion. We have an experimental repository at Github which is updated from the canonical subversion repository every 4 hours.
Using the Github Repository
Non-Committers
Just clone the repository as usual:
git clone git://github.com/Gnucash/gnucash.git
Note that the default branch is trunk, not master which is normal for git. If that bothers you, just make a tracking branch named master:
git branch -t master refs/heads/trunk
When you have patches, use
git diff > patchfile
in the root directory of your local repository to prepare them; then add the patchfile as an attachment to the appropriate bug report.
If you have a Github account, you can fork Gnucash from within Github and clone your forked repository. This allows you to publish your fork and allows Gnucash developers to pull your changes. Please don't use the Github "pull request" mechanism; we can't work directly in the Github repository because it would break synchronization with subversion.
Committers
Set up
Committers start by cloning the repository the same way. Since changes need to be tagged with the subversion revision, no-one should push to the Git repository; a good way to make sure that this doesn't happen by mistake is to use the same read-only URI given above for non-committers. Alternatively, fork the Gnucash repository to your Github account and clone that (use the read-write URI in that case).
Next download git-update, a shell script to pull changes from github and fixup the branch references for git svn. Put it somewhere on your path.
Change directory to your new local repository and run
git svn init --stdlayout svn+ssh://you@svn.gnucash.org/repo/gnucash git-update
That's it. Always use git-update instead of git pull. If you forget and try to use git svn, you'll get errors because the refs that git svn can see won't match the ones in head. If you forget and run git pull by mistake, no big deal, just run git-update and everything will be fixed up.
Committing
git svn dcommit
Will commit your changes back to the subversion repository.
Branching and Merging
This is the whole point of the exercise, right? In order to not make a mess in the subversion repository, we have to be careful to keep our Git branches in Git and not bleed them into subversion by mistake. Once a branch is created in Subversion, it can be merged exactly once back into trunk (or its parent subversion branch), but it can be rebased or cherry-picked as much as you like.
What's the difference? When Git merges, it creates a new reference with more than one parent. It knows when assembling a working copy how to follow those multiple parents and apply their changes in order to produce the target version. A rebase on the other hand patches the target branch for each revision in the supplying branch, creating a new set of references. Cherry-pick does the same as rebase except that it only applies selected revisions.
Subversion doesn't understand this "parent" thing, so when you dcommit a merge revision, git svn basically rebases the merge into subversion. That's fine, but if you have more than one merge between branches (especially if they go in both directions, which is pretty common in Git), git svn will get confused, either when creating the commits into svn or when extracting them to update Github. By doing the rebase yourself, git remains in control of the process and can keep the revision stream to subversion nice and linear.
Collaboration
So Subversion can't see our Git branches. What do we do if several developers need to work together on a feature?
There are several ways to go about it: You can pass patches between you over email, chat, or carrier pigeon; Git is designed to handle that easily (except for carrier pigeon transport, as that requires retyping the patch, which is a pain). You can arrange for all of your repositories to be available on the net, and git pull amongst yourselves. Or you can use one of the public repositories like Github and Gitorious to manage your changes.