- 1 Introduction
- 2 Using the Github Repository
- 2.1 User and "Normal" Contributors
- 2.2 Core Developers
- 2.2.1 About Write Access
- 2.2.2 Set up
- 2.2.3 Committing
- 2.2.4 Branching and Merging
- 2.2.5 Link Bugzilla Entries
- 2.2.6 Patches and Pull Requests
- 3 Collaboration
- 4 Accessing GnuCash BugZilla from Git
- 5 Related Topics
The GnuCash project uses Git to manage the code, documentation and website sources.
If you are new to version control or to using git, you may find it useful to read An Introduction to Git for more information about specific git commands, how they are used in the process of modifying GnuCash, and how to submit changes for review using pull requests (preferred) instead of patches.
will give you a list of usual commands and
git help <command>
will show you the manual page of that command.
There are several GUIs available for git, e.g.:
- git gui
- gitk (shows the history of the different #Branches graphically)
- SourceTree for Windows or Mac
and most IDEs have plugins for it.
While you enter most commands you are working on your local repository. To set it up, you need to connect it with one or more servers, which host the remote repositories and clone that onto your local computer or fork it into your personal github repository.
code.gnucash.org is the server that hosts the canonical git repository, this wiki, Mailing Lists, IRC logs, the nightly builds of the documentation and API docs (via Doxygen) for both branches, and automated win32 builds. Access to this repository is limited to core developers who have been given ssh keys; contributors without commit permissions will not access this repository directly.
GitHub is a web-based Git repository hosting service.
These are updated from the primary repository by commit hooks, so barring technical problems changes appear in these repositories within a few seconds of being committed to the primary.
They host since 2014-02 all GnuCash repositories:
- gnucash.git: the program,
- gnucash-docs: user documentation,
- gnucash-htdocs: Webserver, if you cloned/forked it before 2013-01 see Htdocs Split,
- gnucash-on-osx: Gtk-OSX moduleset, gtk-mac-bundler bundles, and ancillary files for creating GnuCash OSX Application Bundle.
- gnucash-on-windows: windows installer and build script moved here from gnucash/packaging.
See the full list at github.com/Gnucash.
Gnucash uses a variation of the Git Flow process for managing changes. Think of maint as "lower", unstable as "intermediate" and master as "higher". Branches are periodically merged "upwards", meaning that maint is merged into master. When unstable exists "upwards merging happens in three stages instead: maint is merged into unstable and unstable into master. Merges are done at least at every release but generally more often as it's much easier to manage merge conflicts when there are fewer commits. Developers are encouraged to merge upwards immediately after making a big change so that they can handle the merge conflicts with the new code fresh in their minds.
When we get close to releasing a new stable series culminating the development on the master branch we make a new branch unstable from it and make releases with an odd minor number. For example, leading up to the 2.8.0 release we would have a release series 2.7.x. The releases allow users to help test the program and to try out the new features. unstable is between maint and master in the Git Flow hierarchy, so maint is merged into unstable when it exists and unstable into master. When we decide that it's stable we do a final merge of maint into unstable and delete the maint branch then rename unstable to maint as it's the new stable branch.
There are 3 important branches in our more complex repositories for program and documentation:
- is the default branch in git. New features and their documentation should be based on this branch.
- only exists when we're close to a new major release and will be used to make beta releases from. Anything required to get the beta code into shape for a release should be applied to this branch.
- Bugfixes, translations, improvements of the documentation should usually be applied on this branch.
And you should create temporary working branches based on them for nontrivial patchsets:
git branch bugXXXXXX
- In your local working dir you should checkout one of them, e.g.:
git checkout master
- Later you should recurrently integrate remote changes, but usually only befoe you publish your your changes i.e. by a PR:
- In its default mode,
git pullis shorthand for
git fetch(update your local repo), followed by
git merge FETCH_HEADresulting in an update of your current branchs working dir.
One local repository and multiple working directories
After a normal
git clone you will have
- <working dir> and inside
- .git (your local repository)
Because it is time consuming to rebuild almost everything after you switched between different branches of the program, you can since Git 2.5 
git worktree add <path> [<branch>]
mkdir gnucash cd gnucash git clone https://github.com/Gnucash/gnucash.git maint cd maint git checkout maint git worktree add ../master master git worktree list # show list of worktrees
Getting commits from other branches or repos
The simple form
git cherry-pick [options] <commit>... will apply the changes from one or more commits on your current clean branch. But it is not so often used.
Before you publish your branch you should often run
git rebase [options]. This will inserts new commits from remote or one of your other branches in front of your commits (rewriting the deltas (diffs) of your commits).
Finally usually core developers will
git merge [options] your published working branch into the official branch.
- When you have patches in master, use
git format-patch origin/master..master
- in the root directory of your local working directory to prepare them; then add the patchfile as an attachment to the appropriate bug report.
Using the Github Repository
User and "Normal" Contributors
If you are new to using git, you may find it useful to read An Introduction to Git for more information about specific git commands and how they are used in the process of modifying GnuCash.
Just clone the repository as usual:
git clone https://github.com/Gnucash/gnucash.git
- Because of some major source directory restructuring in 2017 you should increase the
merge.renamelimitfrom its default of 1000 in your gnucash repository:
git config merge.renameLimit 3000
- Else the history gets broken and rebasing master on maint will produce strange results.
If you have a Github account or wish to send #Pull Requests, you can use Github's fork feature to set up a clone of the one of the GnuCash repositories. Then, you would clone from that repository instead (note that this is your personal read-write enabled clone):
git clone firstname.lastname@example.org:<YOUR-GITHUB-USERNAME>/gnucash.git. Note that this clone command takes the URL in a different format.
git push origin master. Later, you can issue a #Pull Request to have your changes incorporated into the project.
|Depending on your access rights you might continue with ...||#Pull Requests||#Core Developers|
If you prefer, you can use a GitHub Pull Request instead of attaching a patch to a bug.
- Fork the Gnucash/gnucash or Gnucash/gnucash-docs repo on GitHub. You'll need to create a GitHub account if you haven't got one already and set it up for ssh access. In the example below, we'll assume a GitHub userid of "Me". Substitute your real id.
- Add that branch as a remote in your local repository and push your working branch to it:
git remote add github ssh://email@example.com/Me/gnucash git branch -u github working-branch
- Perhaps an easier approach is to replace the push url:
git remote set-url --push origin firstname.lastname@example.org/Me/gnucash git branch working-branch
- apply your changes and
- Now log in to your GitHub account, go to your forked gnucash repository, select working-branch from the pick list, and click pull request. It's above the "last commit" line on the right in the directory view.
- In the resulting form, give your pull request a title and describe its motivation. If it's associated with a bug, use the bug number and title for your title and paste the bug URL into the description. Note that GitHub descriptions use Markdown and that there's a preview tab to help you make sure that everything looks the way you want it.
- Click the Send Pull Request button to the right of the description block.
- If a developer requires changes to your pull request, amend your commits as necessary and force-push your branch. Don't make any changes to that working branch that aren't associated with the pull request!
- Once the pull request has been either merged or rejected, you can delete the branch:
git branch -D working-branch git push github :working-branch
- If you want to continue in between with something else create another branch.
If you're going to be submitting patches:
- Create a branch to work in:
- Bug fixes should branch off of maint unless the bug applies only to the unstable version.
- New features must branch off of master.
The following example is for a new feature; substitute maint for master if you're doing a bug-fix.
- Use a particular working branch for only one bug or feature. This will make it much easier to make changes and generate new patches should that prove necessary.
git checkout master git branch working-branch
- Rebase your working branch onto the target branch often so that you stay in sync:
git rebase master working-branch
- Open a bug in Bugzilla to attach your patch to if one doesn't already exist.
- Write good commit messages in which the bug number and summary are the first line. Skip one line, then describe the patch. For example:
[Bug 673193] - Possible Register migration to TreeView Update the old register rewrite branch to work with the currently-released Gtk2.
- Use git rebase -i (interactive) as necessary to make a clean series of patches for complex changes.
- Be sure to do a fresh rebase from the target branch and a make check to ensure that everything works
- Use git format-patch to create the actual patches from your commits:
git rebase master working-branch git format-patch master
- Attach the resulting patch(es) to the bug report.
- If a committer asks you to make changes, revise your original commit and make a new patch. Don't submit a patch to be applied on top of an old one. git-rebase -i can be very helpful if you have a series of patches.
About Write Access
While it is possible for new developers to get write access, the project is quite conservative with giving out new SSH write accounts. For occasional changes, people are encouraged to use the procedures outlined above. People can get added as developers if they stick around, supply lots of patches, become highly involved in the project, hang out on IRC, and generally show some level of clue and prove some level of trust.
Note: this set up presumes you already have commit access to the GnuCash repositories on code.gnucash.org. If you don't but believe you should, ask for this on the gnucash-devel mailing list.
Generate your ssh key pair
Under Linux or under Windows with MSYS
To set up ssh with the MSYS client, proceed exactly as here.
You'll need to generate a key-pair and provide the public half to the GnuCash repository administrator. To generate a key pair use
ssh-keygen -t rsa -b 1024 -f gnucash-key
- You can use any name you like instead of "gnucash-key".
- You will also be prompted for a passphrase, with the option to leave it blank. If you provide a passphrase, you will be prompted to provide it every time you use your private key. If you don't, anyone who gains access to your private key can connect to whatever servers you protect with it.
- You will find your private gnucash-key and public gnucash-key.pub keys in
- If something goes wrong with the next command, your IP will get blocked from all services running on code.gnucash.org for one hour.
Once you have the key configured correctly and have provided it to the GnuCash repository administrator, try
ssh -i gnucash-key email@example.com
You'll get the usual ssh question about the fingerprint for a new host. It should be 20:23:3d:df:f3:13:34:c1:32:ca:11:77:24:21:98:01. If it is, answer "yes" to add it to your known hosts file. If you get a message followed by a list of repositories, your setup is correct and you can proceed.
Next, you'll want to to configure your local ssh client to always provide this key when connecting to code.gnucash.org. In addition, ssh should always connect as user 'git'.
On linux, you can set this up by adding the following lines in your ssh config file (~/.ssh/config):
Host code.gnucash.org IdentityFile ~/.ssh/gnucash-key User git
- Then you can shorten the call from above to
(Continue with #Clone the Repositories)
Under Windows with Putty for TortoiseGit
1. Use PuttyGen to convert your private key into Putty format. Launch puttygen, click the "load" button and select your private key file, then click the "save private key" button to save it in putty format.
2. Set up a Putty profile: Start Putty.
- Set the Host URL to code.gnucash.org, port 22 on the Session page
- Open Connection:SSH:Auth and at the bottom of the panel, for "Private key file for authentication" browse for the converted keyfile you made in the previous step.
- Open Connection:Data and enter 'git' in the "Autologin username" text entry.
- Return to the Session panel, enter a name (if you use code.gnucash.org configuring TortoiseGit will be less confusing) in the text entry named "Saved Sessions" and click the "save" button.
- Click "open". If everything is done correctly, a command window will open and you'll see that message about terminal sessions not being allowed. If you are instead prompted for a password, you have messed up the username or key somehow and will need to contact the server admin to get your IP address unblocked.
- (Continue with #TortoiseGit on Windows)
Clone the Repositories
Now clone the Github repository the same way as #Non-Committers. Since changes should not be pushed to the github 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 add the repository on code.gnucash.org as a second remote, for example as 'upstream'.
git remote add upstream firstname.lastname@example.org:gnucash
Perhaps a better approach is to replace the push url:
git remote set-url --push origin email@example.com:gnucash
That avoids confusion where to push and where to fetch.
- (Continue with #Committing)
TortoiseGit on Windows
- Right-click a folder in Windows™ Explorer and select TortoiseGit:Settings. At the bottom of the Network panel of the resulting dialog box, click the "Browse" button for SSH Client and navigate to C:\Program Files\TortoiseGit\bin\TortoisePlink.exe, click "open" in the file chooser, the "OK" to dismiss the Settings box.
- Right-click on a folder into which you want to check out (or already have checked out) Gnucash. If it's a fresh checkout, select TortoiseGit Checkout; otherwise select TortoiseGit:Relocate. Enter the URL as ssh://the-putty-session-name/gnucash. (Remember earlier where we said it would be less confusing if you use code.gnucash.org for the session name? That's because if you did the URL will be ssh://code.gnucash.org/repo/gnucash.)
You should now be able to commit changes via TortoiseGit.
Committing is simple:
- after editing
git add <list of new files> # Register new files git mv <old name or path> <new name or path> # Rename or move files git rm <list of obsolete files> # Remove files from your repo git commit
These above commands are used to record your changes locally.
git push upstream local-branch:remote-branch
Will push your changes back to the master repository.
Branching and Merging
The "canonical" repositories at code.gnucash.org and their mirror at github.com/Gnucash have 2 active branches:
master is the development branch. All new features should be committed to this branch and this branch only. Unstable releases during the beta period leading up to a new stable release series will be tagged on this branch and the tarballs generated from the tag commits. Bugs reported against an unstable release should be checked to see if they exist on the stable release; if they do they should be reassigned to the stable release and fixed on maint, then merged.
- N.B. If for some reason a change is committed to master that should have been done in maint, cherry-pick that commit to maint. Merging master->maint would add all of the development changes into maint, which would be bad.
maint is the current stable release branch. All bugs reported on the released version should have the fixes committed to this branch and then merged into master. Stable releases will be tagged on this branch and the tarballs generated from the tag commits.
There are also archival branches, one for each stable release series no longer under development. Note that before 2.6 we used Subversion or CVS for version control and the practices were different, so you'll see different commit patterns when looking at historical branches.
The gnucash repository contains an archive branch which tracks master up to the point that the last subversion feature branch (webkit, if you're curious) was merged, except that new merge commits have been added to link the feature branch merges. It shows the merge points in the right order, but the merge commit dates are all from early 2014. It is of historical interest only.
There are several abandoned feature branches which were never integrated into GnuCash. They are also present for historical interest only.
Bugs and New Features
To repeat the policy in the description of the active branches:
- Bug fixes should always be rebased onto the maint branch then merged to master unless either they don't affect maint or they are not going to be fixed on maint because the required changes are complex enough that it would risk making maint unstable.
- New Features are always rebased or merged onto master. New features are not allowed on maint.
When and how to use branches depends on the complexity of the changes:
- Small changes, which can be completed quickly and in a single commit, do not require a feature branch.
- Larger changes, which might
- require more than one commit or
- take more than a few hours to write and test
- should be done on a private branch which is rebased onto the appropriate main branch before pushing the changes to the main repository. This helps keep the main branch's history linear, which in turn makes it easier to read and displays better in a graphical tool.
- Major changes,
- which are completed in stages which are made public in parts or
- which for any reason are best visualized as standing apart from the main branch,
- should be merged with --no-ff to prevent them from fast-forwarding the main branch.
Bug Fix Feature Branch Example
git checkout -b my-bug-fix maint # make changes, commit, test, fix, etc. git checkout maint git pull --rebase git rebase maint my-bug-fix # make && make check to ensure that you're not pushing a broken build! git push upstream maint git checkout master git pull --rebase git merge maint # rebuild and make check again git push upstream master
Major Feature Branch Example
git checkout -b my-new-feature master # write and test the first phase of your feature, committing often. git checkout master git pull --rebase git merge --no-ff my-new-feature # rebuild and make check for safety git push upstream master git checkout my-new-feature # write the next phase and repeat until done.
Caution: When switching the branch you should cleanup your build dir to avoid "strange behavior". At least you should run make distclean before, but better might be
cd <yourbuild dir> rm -rf * && ../configure "$YOUR_PARAMETERS" && make && make check
after switching. In case you are building intree you can run
git clean -fdx -e /.project -e /.cproject -e /.autotools -e /.settings/
instead to remove everything not in the repository with a few exceptions (-e ...). Above exceptions are files, where Eclipse stores its settings.
Resolving Merge Conflicts
Sometimes, e.g. after a new release, the first merge in gnucash-docs will result in an conflict about the version number:
git status # On branch master # You have unmerged paths. # (fix conflicts and run "git commit") # # Changes to be committed: # : # Unmerged paths: # (use "git add <file>..." to mark resolution) # # both modified: configure.ac :
configure.ac will now contain a section
<<<<<<< HEAD AC_INIT(gnucash-docs, 2.6.99) ======= AC_INIT(gnucash-docs, 2.6.4) >>>>>>> maint
Just remove the markers and the wrong section with your preferred editor.
Don't forget to run git commit -a to tell git, you are ready!
- Do not confuse
Link Bugzilla Entries
Often commits are related to Bugzilla entries. In this case the commit message should contain
- Bug <bug number>:<bug title> or
- Bug <bug number> - <bug title>.
You can specify it as the first line if the commit fully fixes the related bugzilla issue, or mention it in the body of the commit message otherwise.
Adding these references will make it easier for committers to use the git bz command while manipulating the commits.
Patches and Pull Requests
- Because of our configuration with code.gnucash.org as canonical repository it is strongly discouraged to apply any changes directly to the mirror repositories on Github. Never use GitHubs merge or edit tools!
A common committer duty is handling patches and pull requests from non-committers. The procedure for both is:
- Review the code for formatting, style, good coding practice, good commit message, etc. Make comments and get the submitter to make any necessary changes.
- Download and apply the patch to the appropriate branch. If the change is complex you may want to make a local branch to work in.
- Build and test. Discuss any problems with the submitter and get the patch in good shape, ready to commit.
- If the patch is on the maint branch, do a test merge onto master. Resolve any merge issues with the submitter; if necessary, get a "patch to the patch" to resolve the merge conflicts.
- Once everything is ready, merge your working branch into master or maint:
- Reset your local maint and/or master branches to remove any test merges.
- Pull them to get any commits others might have pushed while you're working.
- Apply the final patches or merge your working branch. When applying take care the patches are committed with the appropriate authorship.
- If the patches were created with git format-patch and hence applied using git am this should be ok.
- Also if the patches are in another repository or branch and you use git pull to apply them the author should be ok as well.
- If the patches came as ordinary diff files to be applied with git apply, you should commit these changes with git commit --author "name <email>" with the proper author name and e-mail filled in.
- Merge maint into master if required; if there's a "patch to the patch" to handle conflicts between maint and master, use --strategy=theirs to the merge, then apply the repair patch and commit 'amending the merge commit:
git checkout master git merge --strategy=theirs maint git apply patch-to-the-patch git commit -a --amend
- Push the results
- Close the pull request or mark the patches "Committed" in Bugzilla.
Pull Request Notes
- When processing a pull request it's safest to download the pull request as a (series of) patch(es). When you pull from the submitter's GitHub repository branch you risk conflicts because it hasn't been rebased to match the current state of the branch you're pulling to, though you can avoid that by making a working branch from the main branch commit that's at the base of the submitter's working branch. There may also be problems if the submitter has made changes to the working branch after making the pull request.
- Note that code review comments can be made inline from the Files Changed tab of the pull request page on GitHub: click on the commit, which displays the diff-patch, and hover over the code snippet which will bring out a '+' button to add a comment for a particular line.
Adding a remote only to apply a pull request is not really necessary. Instead pull the branch from the PR directly into your local repo using "git pull". It takes some shuffling of the information provided by the PR:
For example, if you get a PR against the gnucash repo with the following message (taken from the real PR#163):
0-wiz-0 wants to merge 2 commits into Gnucash:master from 0-wiz-0:master
I would locally run this command (with master being checked out and fully up to date with master on code.gnucash.org):
git pull https://github.com/0-wiz-0/Gnucash master
If master on code.gnucash.org has diverged from 0-wiz-0's master branch, this will trigger a merge action, otherwise it would be a fast-forward.
- I used to rebase non-fast-forward PR's to avoid the merge but have stopped doing so for all but the most trivial PRs. By not rebasing github will automatically close the PR as as soon as the merge result is pushed into the primary repo. After a rebase however one needs to manually close the PR on github. Also a rebase makes it harder for the author of the PR to sync his local repo with our primary one after the PR is pulled.
Here is a breakdown of the relevant info in the PR message compared to the git pull command:
[github-user] wants to merge x commits into Gnucash:[target-branch] from [github-user]: [source-branch]
There's an implicit bit of information as well, namely which [repo] the PR is targetting. Obviously you should work in a local repo for the same source base as in github. So if the PR is against gnucash-docs, you need to do the git-pull in your local gnucash-docs repo. I mention this, because you need this bit of information in your git-pull command as well.
So the above translates into
- go to the proper local repo
- check out [target-branch] (master in the example, but can be maint as well for other PR's)
- make sure this branch is up to date with code.gnucash.org (using 'git pull' without any arguments, assuming you don't have local, non-pushed work on your primary branches. You don't, right?)
- then formulate the pull from another remote (from the [github-user]'s repo):
git pull https://github.com/"$github-user"/"$repo" "$source-branch"
- If it asks for a password you might have mistyped something.
It's slightly more typing than clicking the fancy button on github, but avoids the need to make each new repo in a PR a remote.
- Final note
- This technique can be used to pull from any other repository (online or not) as long as the git command can reach the other repository. So the repository URL can be a github url (https://github.com/...), but equally a url to another online site that hosts repositories, or even a file path to another repo on your own PC. For more info search the git help information on repo urls.
With rare exceptions we don't want to clutter the master repository with feature branches, so how can two developers collaborate on one? 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 [Really?]). 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 or Gitorious to manage your changes.
Accessing GnuCash BugZilla from Git
There is a plugin, called git-bz, written for Git that allows it to talk to BugZilla and do things with bugs like attach patches, add comments, mark as fixed, etc.–all from the command line. See the git-bz page for details.
- An Introduction to Git has basic suggested work flow for modifying GnuCash and more details about what each git command does for those new to git.
- Documentation_Update_Instructions focuses specifically on documentation updates.
- GitHub Help in particular fork-a-repo.
- Git vs Svn has some background on conceptual differences between svn and git. This may help people with a strong svn background to make the switch to git.
- Purely for historical interest:
- Htdocs Split: the gnucash-htdocs repository has been used to store both the website and a compiled version of our documentation ...
- Git Migration tracked the required changes to our infrastructure and support code before we were able to switch to a pure git based workflow.
- GnuCash has been maintaining its source code in a hybrid svn-git system for a while. It has now moved on to a pure git environment. We had some documentation for this hybrid setup as well. The current page's history will reveal how a user had to configure her local setup, Git_Svn_Mirror explains what was needed on the server side.
Other options exists as well; feel free to edit this wiki page.