Difference between revisions of "Git"

From GnuCash
Jump to: navigation, search
m (What is Git?)
(Introduction: Link repos in #Repositories, not #GitHub)
 
(180 intermediate revisions by 7 users not shown)
Line 1: Line 1:
= What is Git? =
+
{| class="wikitable" style="margin: auto;"
 +
! scope="row"|Languages
 +
| | [[He/{{PAGENAME:גיט}}|עִברִית]]
 +
|}
  
[http://git-scm.com/ Git] is a distributed version control system (VCS) originally developed by Linus Torvalds for managing Linux source code without requiring a central server. It is also the primary VCS used by the [http://www.gnome.org Gnome] and [http://www.freedesktop.org Free Desktop] projects. You can get the latest version for your system and read a rich variety of online documentation at [http://git-scm.com/ Git's Home]. In particular, ''Pro Git'' by Scott Chacon is available in several languages for free online reading at [http://git-scm.com/book Git Book], where you can also download the English version as a PDF, ebook, or mobi.
+
[https://git-scm.com/ Git] is a ''[{{URL:wp}}Distributed_version_control distributed]'' '''[{{URL:wp}}Version_control version control system]''' (VCS). The GnuCash project uses Git to manage it's sources (code and bundles, docu and website).
  
= What has that to do with Gnucash? =
+
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.
  
We are in the process of converting from Subversion to Git in order to take advantage of its branching and merging facilities, which are much richer than those provided by Subversion. Our public repositories are mirrored on Github: for [https://github.com/Gnucash/gnucash code], [https://github.com/Gnucash/gnucash-docs documentation], and for the [https://github.com/Gnucash/gnucash-htdocs website]. 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.
+
[[Category:Development]] [[Category:Git]]
  
= Using the Github Repository =
+
== Introduction ==
  
'''Note''': is your local GnuCash git repository from before January 25, 2013 and you haven't converted it yet ? Read the  [[#Conversion Notice]] below. You can ignore this for more recent clones.
+
=== Server ===
 +
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 [[#Set-up|clone]] that onto ''your local computer'' or [[#GitHub Users|fork]] it into ''your personal github repository''.
  
== Non-Committers ==
+
==== {{BuildServer}} ====
=== Set-Up ===
+
<tt>{{BuildServer}}</tt> is the server that hosts the '''canonical git repository''', this wiki, [[Mailing Lists]], [[IRC]] [{{ListURL}}/logs logs], the nightly builds of the [{{URL:Build}}docs/ documentation and API docs] (via [[Doxygen]]) for important [[#Branches|branches]], and automated win32 builds. Write 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.
Just clone the repository as usual:
+
 
 +
==== GitHub ====
 +
'''GitHub''' is a web-based Git repository ''hosting service''.
  
  git clone https://github.com/Gnucash/gnucash.git
+
Our '''public repositories''' are mirrored on GitHub.
  
Note that the default branch in the gnucash and gnucash-docs repositories is <tt>trunk</tt>, not <tt>master</tt> which is normal for git. gnucash-htdocs uses master as default branch already.
+
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.
  
If you prefer looking at a master branch in gnucash or gnucash-docs, just make a tracking branch named master:
+
=== Repositories ===
 +
They host since 2014-02 all GnuCash repositories:
 +
;General Sources:
 +
:;[{{URL:git}}gnucash gnucash.git]: the program,
 +
:;[{{URL:git}}gnucash-docs gnucash-docs]: its user documentation,
 +
:;[{{URL:git}}gnucash-htdocs gnucash-htdocs]: our webserver; if you cloned/forked it before 2013-01 see [[Htdocs Split]],
 +
;OS specific packages bundling all dependencies:
 +
:;[{{URL:git}}gnucash-on-flatpak gnucash-on-flatpak]: Linux [[Flatpak]],
 +
:;[{{URL:git}}gnucash-on-osx gnucash-on-osx]: Gtk-OSX moduleset, gtk-mac-bundler bundles, and ancillary files for creating GnuCash OSX Application Bundle.
 +
:;[{{URL:git}}gnucash-on-windows gnucash-on-windows]: Windows installer and build script moved here from gnucash/packaging.
 +
See the full list at [https://github.com/Gnucash github.com/Gnucash].
  
  git branch -t master refs/remotes/origin/trunk
+
=== Branches ===
 +
==== Branch Policy ====
 +
===== Git Flow =====
 +
Gnucash uses a variation of the [https://nvie.com/posts/a-successful-git-branching-model/ Git Flow] process for managing changes. Think of <tt>stable</tt> as "lower", <tt>unstable</tt> as "intermediate" and <tt>future</tt> as "higher".{{Git branchs rename.ref}} Branches are periodically merged "upwards", meaning that <tt>stable</tt> is merged into <tt>future</tt>. When <tt>unstable</tt> exists "upwards merging happens in three stages instead: <tt>stable</tt> is merged into <tt>unstable</tt> and <tt>unstable</tt> into <tt>future</tt>. 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 you have patches, use
+
===== Beta Testing =====
 +
When we get close to releasing a new stable series culminating the development on the <tt>future</tt> branch we make a new branch <tt>unstable</tt> from it and make releases with an odd minor number. For example,
 +
:before the next major release we (will) have a series {{BetaSeries}},
 +
:leading up to the 2.6.0 release we had a release series 2.5.x.
 +
This releases allow users to help test the program and to try out the new features. <tt>unstable</tt> is between <tt>stable</tt> and <tt>future</tt> in the Git Flow hierarchy, so <tt>stable</tt> is merged into <tt>unstable</tt> when it exists and <tt>unstable</tt> into <tt>future</tt>. When we decide that it's stable we do a final merge of <tt>stable</tt> into <tt>unstable</tt> and delete the <tt>stable</tt> branch then rename <tt>unstable</tt> to <tt>stable</tt> as it's the new stable branch.
  
  git format-patch origin/trunk..master
+
==== Basics ====
 +
There are 3 important branches in our more complex repositories for ''program'' and ''documentation'':
 +
:;future: ''New features'', dependencies, and their documentation should be based on this branch.
 +
:;unstable: 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.
 +
:;stable: is our default branch in git. ''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:
 +
<code>git branch bugXXXXXX</code>
  
(or <tt>git diff</tt>) in the root directory of your local repository to prepare them (again not applicable to gnucash-htdocs); then add the patchfile as an attachment to the appropriate bug report.
+
* In your ''local working dir'' you should checkout one of them, e.g.: <syntaxhighlight lang="sh">
 +
git checkout future
 +
</syntaxhighlight>
 +
* Later you should ''recurrently'' integrate remote changes, but usually only before you publish your changes i.e. by a PR: <syntaxhighlight lang="sh">
 +
git pull
 +
</syntaxhighlight>
 +
:In its default mode, <code>git pull</code> is shorthand for <code>git fetch</code> (update your ''local repo''), followed by <code>git merge FETCH_HEAD</code> resulting in an update of your ''current'' branchs ''working dir''.
  
If you have a Github account, it turns out that Github's "fork" feature doesn't play well with the Gnucash repository because of its unusual structure (which in turn is needed to synch it with subversion).
+
===== One local repository and multiple working directories =====
 +
After a normal <code>git clone</code> you will have  
 +
* the main <worktree> as your ''source'' directory and inside
 +
* the hidden <tt>.git</tt> directory with the metadata or administrative files.
 +
Because it is time consuming to rebuild almost everything after you switched between different branches of the ''program'', you can since Git 2.5 [https://stackoverflow.com/questions/6270193/multiple-working-directories-with-git/30185564#30185564]
 +
<syntaxhighlight lang="sh">
 +
git clone --bare …  # to suppress the creation of the main worktree
 +
# or
 +
git clone --mirror … # same, but also track remote branches,
 +
                    # get informed about pull requests as refs
 +
git worktree add <path> [<branch>]
 +
</SyntaxHighlight> to create separate working directories for different branches.
 +
;Example:<syntaxhighlight lang="sh">
 +
mkdir gnucash
 +
cd gnucash
 +
git clone --mirror https://github.com/Gnucash/gnucash.git .git
 +
git worktree add stable stable
 +
git worktree add future future
 +
git worktree list # show list of worktrees
 +
</SyntaxHighlight>
  
Instead, create a repository in your account (you can name it whatever you like, but calling it Gnucash is likely to minimize confusion), then clone the Gnucash/gnucash repository on your local computer. Add your Github Gnucash repo as a remote
+
===== Getting commits from other branches or repos =====
 +
* The simple form '''<syntaxhighlight lang="sh" inline>git cherry-pick [options] <commit>... </syntaxhighlight>''' will apply the changes from one or more commits on your ''current clean branch''. This is very handy if you want to reorder your patches or amend an older patch than the last.
  
  git remote add myname-github git@github.com:myname/gnucash.git
+
* Before you publish your branch you should often run '''<syntaxhighlight lang="sh" inline>git rebase [options]</syntaxhighlight>'''. 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).
 +
:Because the diffs will be rewritten, the hash/ID of the commits change and it should not be used on already published branches. Although, if the core developers agree, it can be used together with a ''forced push''.
  
and then you can push to it as usual
+
* Finally usually core developers will '''<syntaxhighlight lang="sh" inline>git merge [options]</syntaxhighlight>''' your published working branch into the official branch.
  
  git push myname-github trunk
+
===== Patches =====
 +
* When you have patches in <tt>future</tt>, use <syntaxhighlight lang="sh">
 +
git format-patch origin/future..future
 +
</syntaxhighlight>
 +
:or <syntaxhighlight lang="sh">
 +
git diff
 +
</syntaxhighlight>
 +
:in the root directory of your local working directory to prepare them; then add the patchfile as an attachment to the appropriate bug report.
  
{|cellpadding="20"
+
== Using the Github Repository ==
| Continue with ...
 
|[[#Committers (for svn-backed repositories)]]
 
|[[#Committers (for pure git repositories)]]
 
|}
 
=== Patches ===
 
If you're going to be submitting patches:
 
* Create a branch to work in. If you work directly in a subversion-controlled branch you'll have merge problems when your patches are accepted because git-svn munges the commit message and consequently changes the hash. We prefer that patches are to the <tt>trunk</tt> branch. If the patch needs to be backported, the developer who commits it to subversion can modify the commit message, but if the code in the area you're working on has diverged significantly you can help out by providing separate patches (you'll need two working branches in that case).
 
  git checkout trunk
 
  git branch working-trunk
 
* Rebase your working branch onto the target branch often so that you stay in sync:
 
  git rebase trunk working-trunk
 
* 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 two lines, then describe the patch. Skip another line and add "Author: Your Name <your.email@somewhere.com>" because subversion doesn't have an Author field and we want you to get credit. For example:
 
  [Bug 673193] - Possible Register migration to TreeView
 
 
 
 
 
  Update the old register rewrite branch to work with the currently-released Gtk2.
 
 
 
  Author: John Doe <not.real@gnucash.net>
 
* Use <tt>git rebase -i</tt> 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 <tt>git format-patch</tt> to create the actual patches from your commits:
 
  git rebase trunk working-trunk
 
  git format-patch trunk
 
* Attach the resulting patch(es) to the bug report.
 
  
== Committers (for svn-backed repositories) ==
+
=== User and "Normal" Contributors ===
Currently these GnuCash repositories are svn backed:
 
* gnucash
 
* gnucash-docs
 
  
=== Set up ===
+
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.
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/raw/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. Edit it so that the path to the git library directory (5th line) is correct for your installation or set $GITPERLLIB in your environment to point to the location of Git.pm.
+
==== Set-Up ====
 +
Just clone the repository as usual:
 +
<syntaxhighlight lang="sh">
 +
git clone https://github.com/Gnucash/gnucash.git
 +
</syntaxhighlight>
 +
:;other URLs: https://github.com/Gnucash/gnucash-docs (documentation)
 +
::https://github.com/Gnucash/gnucash-htdocs (website)
 +
::See https://github.com/Gnucash for further repos e.g. with OS/distro specific build scripts.
 +
;Note: Because of some major source directory restructuring in
 +
:: 2017 in GnuCash or
 +
:: 2022 in gnucash-docs
 +
:you should increase the <code>merge.renamelimit</code> from its default of <tt>1000</tt> in your gnucash repository:
 +
:<syntaxhighlight lang="sh">
 +
git config merge.renameLimit 3000
 +
</syntaxhighlight>
 +
:Else the history gets broken and rebasing future on stable will produce strange results.
  
Change directory to your new local repository and run
+
===== GitHub Users =====
 +
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): <code>git clone git@github.com:<YOUR-GITHUB-USERNAME>/gnucash.git</code>. Note that this clone command takes the ''URL in a different format''.
  
  git svn init --stdlayout svn+ssh://YOURNAME@svn.gnucash.org/repo/gnucash
+
With this, you will be able to push your local changes to your forked repository: <pre>git push origin future</pre>. Later, you can issue a [[#Pull Request]] to have your changes incorporated into the project.
  
or
+
{|cellpadding="20"
 +
| Depending on your access rights you might continue with ...
 +
||[[#Pull Requests]]
 +
||[[#Core Developers]]
 +
|}
  
  git svn init --stdlayout svn+ssh://YOURNAME@svn.gnucash.org/repo/gnucash-docs
+
==== Pull Requests ====
 +
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: <SyntaxHighlight lang="sh">
 +
git remote add github ssh://git@github.com/Me/gnucash
 +
git branch -u github working-branch
 +
</SyntaxHighlight>
 +
* apply your changes and <SyntaxHighlight lang="sh">
 +
git push
 +
</SyntaxHighlight>
 +
* Now log in to your GitHub account, go to your forked gnucash repository, select <tt>working-branch</tt> 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, you can either
 +
** ''add'' further commits and ''push'' or
 +
** ''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: <SyntaxHighlight lang="sh">
 +
git branch -D working-branch
 +
git push github :working-branch
 +
</SyntaxHighlight>
 +
* If you want to continue in between with something else create another branch.
  
(if you're working on the documentation). Then
+
==== Patches ====
 +
If you're going to be submitting patches:
 +
* Create a branch to work in:
 +
** '''Bug fixes''' should branch off of ''stable'' unless the bug applies only to the unstable version.
 +
** '''New features''' must branch off of ''future''.
 +
The following example is for a new feature; ''substitute <tt>stable</tt> for <tt>future</tt> 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. <SyntaxHighlight lang="sh">
 +
git checkout future
 +
git branch working-branch
 +
</SyntaxHighlight>
 +
* Rebase your working branch onto the target branch often so that you stay in sync: <SyntaxHighlight lang="sh">
 +
git rebase future working-branch
 +
</SyntaxHighlight>
 +
* 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: <SyntaxHighlight lang="Console">
 +
[Bug 673193] - Possible Register migration to TreeView
 +
 
 +
Update the old register rewrite branch to work with the currently-released Gtk2.
 +
</SyntaxHighlight>
 +
* Use <tt>git rebase -i</tt> (''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 <tt>git format-patch</tt> to create the actual patches from your commits: <SyntaxHighlight lang="sh">
 +
git rebase future working-branch
 +
git format-patch future
 +
</SyntaxHighlight>
 +
* 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. <tt>[https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html git-rebase] -i</tt> can be very helpful if you have a series of patches.
  
  git-update
+
=== Core Developers ===
  
'''''Note''''' Be sure to substitute your svn.gnucash.org userid for "YOURNAME" in that URI!
+
==== About Write Access ====
  
That's it. Always use <tt>git-update</tt> instead of <tt>git pull</tt>. If you forget, <tt>git svn</tt> will error out because the refs that <tt>git svn</tt> can see won't match the ones in refs/remotes/origin. It's no big deal, though, just run <tt>git-update</tt> and everything will be fixed up.
+
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''''' <tt>git svn</tt> doesn't always provide helpful error messages; it will often just fail with a perl error. Aside from messed-up references, it doesn't handle gracefully failing to connect to the svn server.
+
==== Set up ====
 +
'''Note''': this set up presumes you already have commit access to the GnuCash repositories on {{BuildServer}}. If you don't but believe you should, ask for this on the gnucash-devel mailing list.
  
=== Committing ===
+
===== Generate your ssh key pair =====
  
  git svn dcommit
+
====== Under Linux or under Windows with MSYS ======
 +
To set up ssh with the MSYS client, proceed exactly as here.
  
Will commit your changes back to the subversion repository.
+
You'll need to generate a key-pair and provide the public half to the GnuCash repository administrator. To generate a key pair use
 +
<SyntaxHighlight lang="sh">
 +
ssh-keygen -t rsa -b 1024 -f gnucash-key
 +
</SyntaxHighlight>
 +
;Notes: 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'' <tt>gnucash-key</tt> and ''public'' <tt>gnucash-key.pub</tt> keys in <code>~/.ssh/</code>.
 +
;Warning: If something goes wrong with the next command, your IP will get blocked ''from all services'' running on {{BuildServer}} for one hour.
  
=== Branching and Merging ===
+
Once you have the key configured correctly and have provided it to the GnuCash repository administrator, try
 +
<SyntaxHighlight lang="sh">
 +
ssh -i gnucash-key git@code.gnucash.org
 +
</SyntaxHighlight>
 +
You'll get the usual ssh question about the '''fingerprint''' for a new host. It should be <tt>20:23:3d:df:f3:13:34:c1:32:ca:11:77:24:21:98:01</tt>. 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.
  
Git and Subversion treat merges very differently. When Git <tt>merge</tt>s, it creates a new reference with more than one parent. It knows when assembling a working copy or displaying a log 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.
+
Next, you'll want to to configure your local ssh client to always provide this key when connecting to {{BuildServer}}. In addition, ssh should always connect as user 'git'.
  
Subversion doesn't understand this "parent" thing. It merges by making a single patch containing all of the differences between the two branches and applying it to the target branch. The history of how those differences evolved is lost, and there's not even an indication that the changes came from another branch unless the committer mentions it in the commit message.
+
On linux, you can set this up by adding the following lines in your '''ssh config file''' (~/.ssh/config):
 +
:<SyntaxHighlight lang="linux-config">
 +
Host code.gnucash.org
 +
IdentityFile ~/.ssh/gnucash-key
 +
User git
 +
</SyntaxHighlight>
 +
:Then you can shorten the call from above to <SyntaxHighlight lang="sh">
 +
ssh code.gnucash.org
 +
</SyntaxHighlight>
 +
(Continue with [[#Clone the Repositories]])
  
When you run <tt>git svn dcommit</tt>, Git svn must effectively rebase your git changes onto the subversion repository because, well, they're two separate repositories and there can't be any references between the two. If the git history that <tt>git svn dcommit</tt> is committing to subversion contains merges, the revisions on the different merged branches will be flattened into a single chain, because that's what subversion can understand.
+
====== Under Windows with Putty for TortoiseGit ======
 +
For [[https://code.google.com/p/tortoisegit/ TortoiseGit]], you'll also need PuttyGen and Putty from [[https://www.chiark.greenend.org.uk/~sgtatham/putty/ PuTTY]].
 +
Setting up Pageant to work with TortoiseGit is a bit involved, so we'll go through it step-by-step:
  
The problem, of course, is that the subversion history will now look very different from the git history. The subversion view of the history with all of the changes on the target branch will be propagated to the git mirror. When you next update your local repo from the git mirror, the revisions in the target trunk will be added, making a mess of your history.
+
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.
  
To avoid this problem, don't use <tt>git merge</tt> to branches that get <tt>dcommit</tt>ted back to subversion; use <tt>git rebase</tt> or <tt>git cherry-pick</tt> instead. That way the history in your local repository will match what is put on subversion, and what comes back to you from the git mirror. Skillful use of <tt>git rebase</tt> offers [http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#cleaning-up-history substantial control] over what revisions appear in subversion -- but you must do the work in your local Git repo '''before''' calling <tt>git svn dcommit</tt>.
+
2. Set up a Putty profile: Start Putty.  
 +
* Set the Host URL to {{BuildServer}}, 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 <tt>{{BuildServer}}</tt> 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]])
  
It's worth noting here that <tt>git svn rebase</tt> is quite different from <tt>git rebase</tt>: The former is the git svn analog of <tt>git pull --rebase</tt>. That is, it takes all of your local commits and sets them aside, updates your local repository from subversion (creating git commits from each subversion revision, of course) and then replays your commits on top of that. <tt>Git svn dcommit</tt> does that automatically to ensure that it doesn't overwrite other revisions when it commits yours.
+
===== 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).
  
One more thing: It's normal Git practice to make a branch for anything that will take more than one commit to accomplish -- and in Git it's normal to commit small changes often so that you have fine granularity when you change your mind about something, so most git users have lots of branches in their repositories. There's no need to share the vast majority of those branches, and since branching in subversion is expensive, please '''don't''' commit your feature branches back into subversion.
+
Next add the repository on {{BuildServer}} as a second remote, for example as 'upstream'.
 +
<SyntaxHighlight lang="sh">
 +
git remote add upstream git@code.gnucash.org:gnucash
 +
</SyntaxHighlight>
  
To make this more clear, here is an example of a workflow:
+
Perhaps a better approach is to replace the push url:
git checkout trunk
+
<SyntaxHighlight lang="sh">
git-update
+
git remote set-url --push origin git@code.gnucash.org:gnucash
This makes sure you start from the branch that is synchronised with svn
+
</SyntaxHighlight>
git checkout -b feature
+
;Note: This is, when pushing to upstream, it will push to code (which will in turn push to github/Gnucash on your behalf). And when pulling it will pull (read-only) from github/Gnucash.
Create a feature branch to do your work on. While working you create several commits on the branch. When you are ready to push this to subversion do:
+
:*The primary advantage of this configuration is you can't accidentally push to github/Gnucash instead of {{BuildServer}}. And as a side effect you save a few fetches.
git checkout trunk
+
:*The primary disadvantage is this makes it slightly more difficult to detect/recover from a divergence between code and github/Gnucash. Fortunately that rarely happens and to fix that is sufficces to temporarily define one or two extra remotes to separate out the combined upstream.
git-update
+
That's it.
git rebase trunk feature
+
: (Continue with [[#Committing]])
to synchronize trunk with the master git repository again and base your feature changes on the most up to date trunk branch
 
git svn dcommit
 
to send your commits upstream to svn. Now wait until Github gets updated (it takes about 5 minutes) and run
 
git-update
 
git checkout feature
 
git merge trunk
 
And you are ready to continue your work.
 
==== Trouble ====
 
'''Transaction is out of date'''
 
Sometimes when you try to dcommit, it will fail with an error like
 
  Transaction is out of date: File '/gnucash/trunk/src/engine/Account.c' is out of date at /usr/libexec/git-core/git-svn line 590
 
  
This happens most often when you are working in multiple branches and cherry-picking or rebasing back onto trunk. The problem is that there are three separate references involved: refs/heads/trunk (your local working version) refs/remotes/trunk (an intermediate version used by git-svn) and refs/remotes/origin/trunk (the version on Github). Git-update ensures that the latter two match, so if you get this error, that's the first thing to try:
+
====== TortoiseGit on Windows ======
  git-update
+
* 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 <tt>C:\Program Files\TortoiseGit\bin\TortoisePlink.exe</tt>, click "open" in the file chooser, the "OK" to dismiss the Settings box.
If that doesn't work, it might be that git-svn has just gotten out of sorts. The next thing to try is
+
* 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 <tt>ssh://the-putty-session-name/gnucash</tt>. (Remember earlier where we said it would be less confusing if you use <tt>{{BuildServer}}</tt> for the session name? That's because if you did the URL will be <tt>ssh://{{BuildServer}}repo/gnucash</tt>.)
  git svn rebase
 
If that ''still'' doesn't fix the problem, then the problem is that refs/heads/trunk is out of sync with refs/remotes/trunk. To study the problem, a graphical history is helpful: Use <tt>gitk</tt> on X11 or GitX.app on OSX. You'll likely see that the change that's causing the trouble. In the case above, it was a r20935: I had cherry-picked a change from my working branch and dcommitted it, then without waiting cherry-picked some changes from my GSOC student's branch. That set the parent to the new cherry-picks as the revision I had created when I dcommitted, and so when I belatedly ran git-update to get up to date with Github, I had this:
 
        -- C' - D' -- E -- F  (trunk)
 
        /
 
  A -- B -- C -- D  (remotes/trunk & remotes/origin/trunk)
 
  
The solution was
+
You should now be able to commit changes via TortoiseGit.
  git rebase refs/remotes/trunk refs/heads/trunk
 
which got rid of the unwanted C' and D'.
 
If the problem isn't that clear, then note the SVN revision of the last commit the branches have in common (we'll call it rB, but it's going to really be something like r20911). Try
 
  git svn reset rB
 
  git-update
 
and study the graph again to see what should be rebased where.
 
  
== Committers (for pure git repositories) ==
+
==== Committing ====
Currently these GnuCash repositories are pure git repositories:
+
Committing is simple:
* gnucash-htdocs
+
:after editing
 +
<syntaxhighlight lang="sh" highlight=4>
 +
git add <list of new or modified files>      # Tell Git which files to include in the commit
 +
# Important, use this instead of your OSes commands. Else you will loose their history:
 +
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
 +
</syntaxhighlight>
 +
These above commands are used to record your changes ''locally''.
  
=== Set up ===
+
<syntaxhighlight lang="sh">
'''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.
+
git push upstream local-branch:remote-branch
 +
</syntaxhighlight>
 +
Will push your changes ''back to the future'' repository.
  
When you got write access to code.gnucash.org, this write access was associated with an ssh keypair you provided. Now is the time 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'.
+
==== Branching and Merging ====
  
On linux, you can set this up by adding the following lines in your ssh config file (~/.ssh/config):
+
The "canonical" repositories at {{BuildServer}} and their public mirrors at github.com/Gnucash have 2 active branches:
Host code.gnucash.org
 
IdentityFile ~/.ssh/keyname-for-gnucash
 
User git
 
  
Be sure to replace "''keyname-for-gnucash''" with the the real name of your ssh key.
+
'''future''' 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 '''stable''', then merged.
 +
:'''N.B.''' If for some reason a change is committed to '''future''' that should have been done in '''stable''', '''''cherry-pick''''' that commit to '''stable'''. Merging '''future'''->'''stable''' would add all of the development changes into '''stable''', which would be bad.
  
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).
+
'''stable''' 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 '''future'''. Stable releases will be tagged on this branch and the tarballs generated from the tag commits.
  
Next add the repository on code.gnucash.org as a second remote, for example as 'upstream'.
+
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.
  
  git remote add upstream ssh://git@code.gnucash.org/gnucash-htdocs
+
The gnucash repository contains an '''archive''' branch which tracks '''future''' 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.
  
That's it. Contrary to the svn backed repositories, you can use standard git mechanisms to download the most recent changes from the master repository, like <tt>git pull</tt>.
+
There are several ''abandoned feature branches'' which were never integrated into GnuCash. They are also present for historical interest only.
  
'''Note''': it's worth noting that the svn backed repos and the pure git repos use a different main branch for development work:
+
==== Pushing onto another core developer branch ====
* svn backed repos: '''trunk'''
 
* pure git repos: '''master'''
 
  
=== Committing ===
+
It is possible for a developer (Alice) to push to another developer (Bob)'s github branch 'bob-dev'. We *assume* that 'bob-dev' is based on stable.
  
Since this is pure git environment, we can use the usual git mechanisms.
+
Alice will create a branch that mirrors Bob's branch.
  
  git add
+
<syntaxhighlight lang="sh">
  git commit
+
# Same as test-building a PR branch.
These two commands are used to record your changes locally.
 
  
  git push upstream local-branch:remote-branch
+
git fetch
 +
git checkout -b bob-dev stable
 +
git pull https://github.com/bob/gnucash bob-dev
  
Will push your changes back to the master repository.
+
# Edit and commit, then push:
  
=== Branching and Merging ===
+
git push git@github.com:bob/gnucash bob-dev
 +
</syntaxhighlight>
  
TBD The branching and merging strategy still has to be outlined in more detail.
+
==== Bugs and New Features ====
 +
To repeat the policy in the description of the active branches:
 +
* '''Bug fixes''' should always be rebased onto the '''stable''' branch then merged to '''future''' unless either they don't affect '''stable''' or they are not going to be fixed on '''stable''' because the required changes are complex enough that it would risk making '''stable''' unstable.
 +
* '''New Features''' are '''''always''''' rebased or merged onto '''future'''. New features are '''not allowed''' on '''stable'''.
  
The rough idea is probably:
+
When and how to use branches depends on the complexity of the changes:
* Use local branches for your development. As long as you didn't publish those branches, you can locally rebase them to the most recent public branch heads (like trunk, 2.6.x,...)
+
* '''Small changes''', which can be completed quickly and in a single commit, do not require a feature branch.
* When you consider the code in your local branch sufficiently mature, you can merge it into one of the public branches and push the changes upstream.
+
* '''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 <tt>--no-ff</tt> to prevent them from fast-forwarding the main branch.
  
Again, we need to detail this much better. How branches are defined and managed is the core of a good git workflow. A good starting point for our own branching and merging strategy could be these two links (got these from the swig mailing list, which also recently converted to git):
+
'''Bug Fix Feature Branch Example'''
* [[https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html Kernel.org git workflows]]
+
<syntaxhighlight lang="sh">
* [[https://bitbucket.org/petsc/petsc/wiki/developer-instructions-git Git workflow for the petsc project ]]
+
git checkout -b my-bug-fix stable
 +
# make changes, commit, test, fix, etc.
 +
git checkout stable
 +
git pull --rebase
 +
git rebase stable my-bug-fix
 +
# make && make check to ensure that you're not pushing a broken build!
 +
git push upstream stable
 +
git checkout future
 +
git pull --rebase
 +
git merge stable
 +
# rebuild and make check again
 +
git push upstream future
 +
</syntaxhighlight>
  
=== Link Bugzilla Entries ===
+
'''Major Feature Branch Example'''
 +
<syntaxhighlight lang="sh">
 +
git checkout -b my-new-feature future
 +
# write and test the first phase of your feature, committing often.
 +
git checkout future
 +
git pull --rebase
 +
git merge --no-ff my-new-feature
 +
# rebuild and make check for safety
 +
git push upstream future
 +
git checkout my-new-feature
 +
# write the next phase and repeat until done.
 +
</syntaxhighlight>
  
Often commits are related to [[Bugzilla]] entries. In this case the first line should contain
+
'''Caution:''' When ''switching the branch'' you should cleanup your build dir to avoid "strange behavior". At least you should run <tt>make distclean</tt> before, but better might be
* '''<tt>Bug #</tt>''<bug number>''<tt>:</tt>''<bug title>''''' or
+
<syntaxhighlight lang="sh">
* '''<tt>Bug #</tt>''<bug number>''<tt> - </tt>''<bug title>'''''.
+
cd <yourbuild dir>
If ''trac'' sees the hash sign (#), it should create a link to that bugzilla entry.
+
rm  -rf * && ../configure "$YOUR_PARAMETERS" && make && make check
 +
</syntaxhighlight>
 +
after switching. In case you are building intree you can run
 +
<syntaxhighlight lang="sh">
 +
git clean -fdx -e /.project -e /.cproject -e /.autotools -e /.settings/
 +
</syntaxhighlight>
 +
instead to remove everything not in the repository with a few exceptions (-e ...). Above exceptions are files, where [[Eclipse]] stores its settings.  
  
=== Backport Rules ===
+
====== Resolving Merge Conflicts ======
  
While usually commits will be applied to ''master'', sometimes it is desired to '''backport''' them on the ''stable branch'', currently 2.4. There are a few rules to decide, if a commit should be backported:
+
Sometimes, e.g. after a new release, the first merge in gnucash-docs will result in an conflict about the version number:
* If the commit fixes a bug[[#Note|(1)]] that was reported in ''bugzilla'' against the ''stable branch'', the changeset should be backported, but:
+
<syntaxhighlight lang="console">
* The backporting effort should be trivial. If complicated manual intervention is required, backporting should be skipped to maintain stability.
+
git status
* Backports should not require new or stronger ''dependencies.''
+
# On branch future
* If the changeset modifies the ''data model'', it should be split in 2 parts:
+
# You have unmerged paths.
** The part to ''read'' the modified data model should be backported.
+
#   (fix conflicts and run "git commit")
** The part to ''write'' the modified data model should only be applied on trunk.
+
#
:: This would allow a user to test a new main release on one computer while still using the older version on another computer or later on the same computer again without data loss.
+
# Changes to be committed:
 +
#
 +
:
 +
# Unmerged paths:
 +
#  (use "git add <file>..." to mark resolution)
 +
#
 +
#      both modified:      configure.ac
 +
:</syntaxhighlight>
  
If you wish to backport your commit on trunk should contain the mark '''BP''' in a separate line of the comment. That would trigger the prefix '''AUDIT''' to the mails sent to the ''gnucash-patches'' and ''gnucash-changes'' lists.
+
configure.ac will now contain a section
  
====Note====
+
<pre><<<<<<< HEAD
* Backporting only applies for true bugs, meaning errors in the existing functionality or intended use. New features, additions to current functionality, enhancement requests etc. are not considered for backporting, even if the enhancement request was registered in bugzilla against the stable branch.
+
AC_INIT(gnucash-docs, 2.6.99)
 +
=======
 +
AC_INIT(gnucash-docs, 2.6.4)
 +
>>>>>>> stable</pre>
  
=== Current Backport Policy ===
+
Just remove the markers and the wrong section with your preferred editor.
  
Backports should be cherry-picked '''and thoroughly tested''' as soon as possible after committing to ''trunk''/''master''.
+
Don't forget to run <tt>git commit -a</tt> to tell git, you are ready!
 +
;Note: Do not confuse <code>-a</code> = <code>--all</code> with <code>--amend</code>!
  
=== Backport comment format ===
+
==== Link Bugzilla Entries ====
  
This section is adapted from Geert Janssens'
+
Often commits are related to [[Bugzilla]] entries. In this case the commit message should contain
email [http://lists.gnucash.org/pipermail/gnucash-devel/2012-October/034404.html] to the gnucash-devel list.
+
* '''<tt>Bug </tt>''<bug number>''<tt>:</tt>''<bug title>''''' or
 +
* '''<tt>Bug </tt>''<bug number>''<tt> - </tt>''<bug title>'''''.
  
The commit message for trunk should contain, somewhere within the body
+
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.
of the message, a line with only &ldquo;BP&rdquo; on it to indicate this
 
commit is meant to be backported. That helps to check later if all the
 
relevant commits are really backported. It also alters the commit
 
messages that are sent to gnucash-patches and gnucash-changes to begin
 
with &ldquo;AUDIT&rdquo;. The AUDIT/BP marks don&rsquo;t trigger any
 
automatic backporting tasks within the source code management system,
 
but they&rsquo;re still useful for other developers to follow what gets
 
backported and what not.
 
  
The commit message on the commit that goes into the stable branch
+
Adding these references will make it easier for committers to use the ''git bz'' command while manipulating the commits.
essentially uses the same text with two small changes: the line
 
containing the &ldquo;BP&rdquo; mark is removed, and the revision number
 
of the trunk commit is prepended to the message, surrounded with square
 
brackets.
 
  
An example will probably make it much clearer. The commit to trunk
+
==== Patches and Pull Requests ====
would have this message:
+
;Warning: Because of our configuration with {{BuildServer}} 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 ''stable'' branch, do a test merge onto ''future''. 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 ''future'' or ''stable'':
 +
** Reset your local ''stable'' and/or ''future'' 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 ''stable'' into ''future'' if required; if there's a "patch to the patch" to handle conflicts between ''stable'' and ''future'', use <tt>--strategy=theirs</tt> to the merge, then apply the repair patch and commit '''amending'' the merge commit: <SyntaxHighlight lang="sh">
 +
git checkout future
 +
git merge --strategy=theirs stable
 +
git apply patch-to-the-patch
 +
git commit -a --amend
 +
</SyntaxHighlight>
 +
* Push the results
 +
* Close the pull request or mark the patches "Committed" in Bugzilla.
  
<pre>
+
===== Pull Request Notes =====
My latest changes
+
:If there have been changes in the same files that the PR changes there will be ''conflicts'' when you pull in the PR branch. Github will usually indicate that by replacing the green merge button with a warning "This branch has conflicts that must be resolved". There are three ways to resolve the conflicts:
BP
+
# Require the author to rebase their branch and resolve the conflicts themselves, then force-push the branch.
</pre>
+
# Pull the PR branch into a local branch that's current and resolve the conflicts in the resulting merge commit.
 +
# Go to the first commit in the PR and note the parent hash. Branch from there, pull the PR into that branch (it will fast-forward), build and test, then merge that branch into HEAD and resolve the conflicts at that time.
 +
:;Forced Pushes: After the PR author has force-pushed changes to the PR branch git will refuse to fetch it because the history has changed. The safest way to deal with that is to reset your local branch to the last mainline commit and re-pull. You can also use <code>git pull -f ... </code> but if you do check the result carefully to be sure that it did the right thing.
 +
:;Code review comments: They can be made inline from the <tt>Files Changed</tt> 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.
  
Let&rsquo;s assume this got committed in r22445 and now has to be
+
===== Advanced Pulling =====
backported. The message to use on the stable branch will now be:
+
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:
  
<pre>
+
For example, if you get a PR against the gnucash repo with the following message (taken from
[22445] My latest changes
+
the real PR#163):
</pre>
+
0-wiz-0 [1]wants to merge 2 commits into Gnucash:future from 0-wiz-0:future
 +
I would locally run this command (with future being checked out and fully up to date with future on {{BuildServer}}):
 +
<syntaxhighlight lang="sh">
 +
git pull https://github.com/0-wiz-0/Gnucash future
 +
</syntaxhighlight>
  
That&rsquo;s it.  
+
If future on {{BuildServer}} has diverged from 0-wiz-0's future branch, this will trigger a merge action, otherwise it would be a fast-forward.
  
----
+
;Sidenote: 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.
  
Other options exists as well; feel free to edit this wiki page.
+
Here is a breakdown of the relevant info in the PR message compared to the git pull command:
  
[[Development_Process|Back to Development Process]]
+
['''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.
  
[[Category:Development]]
+
So the above translates into
 +
* go to the proper local ''repo''
 +
* depending on the complexity:
 +
** simple PR: check out [''target-branch''] (future in the example, but can be stable as well for other PR's)
 +
** complex PR: create ['''source-branch'''] based on target-branch
 +
* make sure this branch is up to date with {{BuildServer}} (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): <syntaxhighlight lang="sh">
 +
git pull https://github.com/"$github-user"/"$repo" "$source-branch"
 +
</syntaxhighlight>
 +
:;Hint: If it asks for a password you might have mistyped something.
 +
* Additional step for complex PRs: After checking the correctness and potential fixes, merge the source-brancch in the target-branch.
  
== Making a Branch or Tag in the Subversion Repository ==
+
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.
  
As limited as Subversion branches and tags are (and they're the same thing, a complete copy of the revision-controlled tree, just in different subdirectories), Subversion does keep track of branch points. ''Unfortunately, <tt>git svn</tt> does do the branch the wrong way''. It creates a new subdirectory and copies the files itself rather than using the <tt>svn copy</tt> command. This does create the branch or tag, and it looks like it should, but the Subversion repository doesn't know that it's a branch and doesn't know what the parent revision is. The result bites us when we try to update the git repo, because the tag or branch revision is invisible to <tt>git svn</tt>, so it doesn't get echoed into the git repository.
+
;Another approach: is to add "fetch = +refs/pull/*/head:refs/pull/origin/*" to [remote "origin"] in your <tt>.git/config</tt>.
 +
:After a <code>git fetch origin</code> you can i.e. <Syntaxhighlight lang="sh">
 +
git checkout -b PR${PRNR} pull/origin/${PRNR}  # ${PRNR}: Number of the pull request
 +
</Syntaxhighlight> to get a pull request branch based on its number.
 +
:(from https://gist.github.com/Chaser324/ce0505fbed06b947d962#checking-out-and-testing-pull-requests)
 +
:;Pro:This is still possible, after the branch at github.com/"$github-user" was accidently deleted.
 +
:;Con:It is not possible to push a patch onto github.com/"$github-user"'s PR.
  
''Therefore, always do Subversion branches and tags direcly in Subversion, not from git!'' This can either be done in a local Subversion checkout, or directly remotely by the command <tt>svn copy URL-FROM URL-TO</tt>.
+
;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.
  
 
== Collaboration ==
 
== Collaboration ==
  
So Subversion can't see our Git branches. What do we do if several developers need to work together on a feature?
+
With rare exceptions we don't want to clutter the future 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 [[{{URL:wp}}B._F._Skinner#Pigeon-guided_missile Really?]]). 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 or Gitorious to manage your changes.
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.
 
  
 
+
== Accessing GnuCash BugZilla from Git ==
= 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.&ndash;all from the command line. See the [[git-bz]] page for details.
 
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.&ndash;all from the command line. See the [[git-bz]] page for details.
  
= Acknowledgments =
+
== Related Topics ==
  
The workflow was designed by Thomas Ferris Nicolaisen. More information and a nice illustration can be found on his [http://blog.tfnico.com/2010/11/git-svn-mirror-for-multiple-branches.html blog].
+
* [[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.
 +
* [https://help.github.com/ GitHub Help] in particular [https://help.github.com/articles/fork-a-repo/ 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.
  
As noted in the documentation, <tt>git-svn-mirror</tt> is based on a Ruby tool called [http://github.com/nirvdrum/svn2git svn2git].
+
----
  
= Conversion Notice =
+
Other options exists as well; feel free to edit this wiki page.
For the last two years, the Github mirrors have been maintained by an external server. We are in the process of converting to the updates coming from the primary server, code.gnucash.org. As part of that process we decided to clean up the authors file so that the names and email addresses of all of the committers in CVS and Subversion will be correct. That's going to change the SHA-1 hashes on most commits, so it will appear to git like a different set of revisions, which won't merge with existing repos. As a result, the Github repositories will be regenerated and users with existing clones will have to clone them anew.
 
  
If you have been using your gnucash git repository as a convenient way to test the latest code and have no local changes, you'll need only delete and re-clone your repository. If you have local changes, you'll want to preserve them, so instead of deleting the directory, rename it. For the examples we'll call it <tt>gnucash-old</tt>, and we'll clone into <tt>gnucash-new</tt>. That's just to make sure we don't forget which is which. After the import process is complete, you can remove <tt>gnucash-old</tt> and rename <tt>gnucash-new</tt>.
+
[[Development_Process|Back to Development Process]]
 
 
You've been assiduous about always using <tt>git pull --rebase</tt> or better still, <tt>git-update</tt>, right? No? You've got changes mixed into <tt>trunk</tt>? No matter. <tt>rebase</tt> to the rescue: (I'm using <tt>trunk</tt> as an example here, but it could be any tracking branch.)
 
  cd gnucash-old
 
  git pull --rebase #or git-update
 
  git branch -m trunk foo #This is your new feature branch. You can call it anything you like
 
  git branch -t trunk origin/trunk
 
  git rebase trunk foo
 
There. Now all of your changes are in a nice feature branch. You might have to reconcile some conflicts, but better sooner than later, eh? If you already have feature branches -- we'll use <tt>foo</tt> for our example -- just make sure that it's up to date with its tracking branch:
 
  git checkout trunk
 
  git pull --rebase #or git-update
 
  git rebase trunk foo
 
 
 
Now you're ready to import your changes. First prepare <tt>gnucash-new</tt> to know about the existence of <tt>gnucash-old</tt>
 
  cd gnucash-new
 
  git remote add transfer ../gnucash-old
 
  git fetch transfer
 
 
 
And for each branch you wish to import:
 
  git checkout trunk
 
  git checkout -b foo
 
  git cherry-pick transfer/trunk..transfer/foo
 
 
 
That's it. Repeat for each feature branch and tracking branch. When you're done and sure that everything is properly set up, you can
 
  git remote rm transfer
 
to clean the old trees from your new repo. When you're really, really sure that everything is transferred, you can delete <tt>gnucash-old</tt>.
 
 
 
'''Note:''' When you run <tt>git checkout trunk</tt> in <tt>gnucash-new</tt>, git ''should'' respond with
 
  Checking out files: 100% (1247/1247), done.
 
  Branch trunk set up to track remote branch trunk from origin.
 
  Switched to a new branch 'trunk'
 
''If it doesn't'', then it may have gotten confused. If
 
  git log --oneline -n 10
 
doesn't produce the expected results,
 
  git branch -D trunk
 
  git branch -t trunk origin/trunk
 
To get the proper tracking branch.
 
 
 
'''Github Forks:''' If you have made a Github fork you will need to make sure that your local repo is current and then delete the fork and re-fork the regenerated repository, then proceed according to the instructions above, finally pushing any new branches back to your Github fork.
 
 
 
= Related Topics =
 
 
 
* [[Git Migration]] tracks the required changes to our infrastructure and support code before we can switch to a pure git based workflow.
 
* [[Git Svn Mirror]] documents the Git-svn mirror we have set up for GnuCash (referred to above). This may be of interest to people that wish to use a similar configuration for their project.
 
* [[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.
 

Latest revision as of 18:12, 23 September 2024

Languages עִברִית

Git is a distributed version control system (VCS). The GnuCash project uses Git to manage it's sources (code and bundles, docu and website).

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.

Introduction

Server

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

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 important branches, and automated win32 builds. Write 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

GitHub is a web-based Git repository hosting service.

Our public repositories are mirrored on GitHub.

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.

Repositories

They host since 2014-02 all GnuCash repositories:

General Sources
gnucash.git
the program,
gnucash-docs
its user documentation,
gnucash-htdocs
our webserver; if you cloned/forked it before 2013-01 see Htdocs Split,
OS specific packages bundling all dependencies
gnucash-on-flatpak
Linux Flatpak,
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.

Branches

Branch Policy

Git Flow

Gnucash uses a variation of the Git Flow process for managing changes. Think of stable as "lower", unstable as "intermediate" and future as "higher".[1] Branches are periodically merged "upwards", meaning that stable is merged into future. When unstable exists "upwards merging happens in three stages instead: stable is merged into unstable and unstable into future. 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.

Beta Testing

When we get close to releasing a new stable series culminating the development on the future branch we make a new branch unstable from it and make releases with an odd minor number. For example,

before the next major release we (will) have a series 5.9xx,
leading up to the 2.6.0 release we had a release series 2.5.x.

This releases allow users to help test the program and to try out the new features. unstable is between stable and future in the Git Flow hierarchy, so stable is merged into unstable when it exists and unstable into future. When we decide that it's stable we do a final merge of stable into unstable and delete the stable branch then rename unstable to stable as it's the new stable branch.

Basics

There are 3 important branches in our more complex repositories for program and documentation:

future
New features, dependencies, and their documentation should be based on this branch.
unstable
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.
stable
is our default branch in git. 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 future
    
  • Later you should recurrently integrate remote changes, but usually only before you publish your changes i.e. by a PR:
    git pull
    
In its default mode, git pull is shorthand for git fetch (update your local repo), followed by git merge FETCH_HEAD resulting in an update of your current branchs working dir.
One local repository and multiple working directories

After a normal git clone you will have

  • the main <worktree> as your source directory and inside
  • the hidden .git directory with the metadata or administrative files.

Because it is time consuming to rebuild almost everything after you switched between different branches of the program, you can since Git 2.5 [1]

git clone --bare …   # to suppress the creation of the main worktree
# or
git clone --mirror … # same, but also track remote branches,
                     # get informed about pull requests as refs
git worktree add <path> [<branch>]
to create separate working directories for different branches.
Example
mkdir gnucash
cd gnucash
git clone --mirror https://github.com/Gnucash/gnucash.git .git
git worktree add stable stable
git worktree add future future
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. This is very handy if you want to reorder your patches or amend an older patch than the last.
  • 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).
Because the diffs will be rewritten, the hash/ID of the commits change and it should not be used on already published branches. Although, if the core developers agree, it can be used together with a forced push.
  • Finally usually core developers will git merge [options] your published working branch into the official branch.
Patches
  • When you have patches in future, use
    git format-patch origin/future..future
    
or
git diff
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.

Set-Up

Just clone the repository as usual:

git clone https://github.com/Gnucash/gnucash.git
other URLs
https://github.com/Gnucash/gnucash-docs (documentation)
https://github.com/Gnucash/gnucash-htdocs (website)
See https://github.com/Gnucash for further repos e.g. with OS/distro specific build scripts.
Note
Because of some major source directory restructuring in
2017 in GnuCash or
2022 in gnucash-docs
you should increase the merge.renamelimit from its default of 1000 in your gnucash repository:
git config merge.renameLimit 3000
Else the history gets broken and rebasing future on stable will produce strange results.
GitHub Users

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 git@github.com:<YOUR-GITHUB-USERNAME>/gnucash.git. Note that this clone command takes the URL in a different format.

With this, you will be able to push your local changes to your forked repository:
git push origin future
. 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

Pull Requests

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://git@github.com/Me/gnucash
    git branch -u github working-branch
    
  • apply your changes and
    git push
    
  • 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, you can either
    • add further commits and push or
    • 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.

Patches

If you're going to be submitting patches:

  • Create a branch to work in:
    • Bug fixes should branch off of stable unless the bug applies only to the unstable version.
    • New features must branch off of future.

The following example is for a new feature; substitute stable for future 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 future
    git branch working-branch
    
  • Rebase your working branch onto the target branch often so that you stay in sync:
    git rebase future 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 future working-branch
    git format-patch future
    
  • 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.

Core Developers

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.

Set up

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
Notes
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 ~/.ssh/.
Warning
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 git@code.gnucash.org

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
ssh code.gnucash.org

(Continue with #Clone the Repositories)

Under Windows with Putty for TortoiseGit

For [TortoiseGit], you'll also need PuttyGen and Putty from [PuTTY]. Setting up Pageant to work with TortoiseGit is a bit involved, so we'll go through it step-by-step:

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 git@code.gnucash.org:gnucash

Perhaps a better approach is to replace the push url:

git remote set-url --push origin git@code.gnucash.org:gnucash
Note
This is, when pushing to upstream, it will push to code (which will in turn push to github/Gnucash on your behalf). And when pulling it will pull (read-only) from github/Gnucash.
  • The primary advantage of this configuration is you can't accidentally push to github/Gnucash instead of code.gnucash.org. And as a side effect you save a few fetches.
  • The primary disadvantage is this makes it slightly more difficult to detect/recover from a divergence between code and github/Gnucash. Fortunately that rarely happens and to fix that is sufficces to temporarily define one or two extra remotes to separate out the combined upstream.

That's it.

(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.orgrepo/gnucash.)

You should now be able to commit changes via TortoiseGit.

Committing

Committing is simple:

after editing
git add <list of new or modified files>       # Tell Git which files to include in the commit
# Important, use this instead of your OSes commands. Else you will loose their history:
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 future repository.

Branching and Merging

The "canonical" repositories at code.gnucash.org and their public mirrors at github.com/Gnucash have 2 active branches:

future 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 stable, then merged.

N.B. If for some reason a change is committed to future that should have been done in stable, cherry-pick that commit to stable. Merging future->stable would add all of the development changes into stable, which would be bad.

stable 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 future. 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 future 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.

Pushing onto another core developer branch

It is possible for a developer (Alice) to push to another developer (Bob)'s github branch 'bob-dev'. We *assume* that 'bob-dev' is based on stable.

Alice will create a branch that mirrors Bob's branch.

# Same as test-building a PR branch.

git fetch
git checkout -b bob-dev stable
git pull https://github.com/bob/gnucash bob-dev

# Edit and commit, then push:

git push git@github.com:bob/gnucash bob-dev

Bugs and New Features

To repeat the policy in the description of the active branches:

  • Bug fixes should always be rebased onto the stable branch then merged to future unless either they don't affect stable or they are not going to be fixed on stable because the required changes are complex enough that it would risk making stable unstable.
  • New Features are always rebased or merged onto future. New features are not allowed on stable.

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 stable
# make changes, commit, test, fix, etc.
git checkout stable
git pull --rebase
git rebase stable my-bug-fix
# make && make check to ensure that you're not pushing a broken build!
git push upstream stable
git checkout future
git pull --rebase
git merge stable
# rebuild and make check again
git push upstream future

Major Feature Branch Example

git checkout -b my-new-feature future
# write and test the first phase of your feature, committing often.
git checkout future
git pull --rebase
git merge --no-ff my-new-feature
# rebuild and make check for safety
git push upstream future
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 future
# 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)
>>>>>>> stable

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!

Note
Do not confuse -a = --all with --amend!

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

Warning
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 stable branch, do a test merge onto future. 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 future or stable:
    • Reset your local stable and/or future 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 stable into future if required; if there's a "patch to the patch" to handle conflicts between stable and future, use --strategy=theirs to the merge, then apply the repair patch and commit 'amending the merge commit:
      git checkout future
      git merge --strategy=theirs stable
      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
If there have been changes in the same files that the PR changes there will be conflicts when you pull in the PR branch. Github will usually indicate that by replacing the green merge button with a warning "This branch has conflicts that must be resolved". There are three ways to resolve the conflicts:
  1. Require the author to rebase their branch and resolve the conflicts themselves, then force-push the branch.
  2. Pull the PR branch into a local branch that's current and resolve the conflicts in the resulting merge commit.
  3. Go to the first commit in the PR and note the parent hash. Branch from there, pull the PR into that branch (it will fast-forward), build and test, then merge that branch into HEAD and resolve the conflicts at that time.
Forced Pushes
After the PR author has force-pushed changes to the PR branch git will refuse to fetch it because the history has changed. The safest way to deal with that is to reset your local branch to the last mainline commit and re-pull. You can also use git pull -f ... but if you do check the result carefully to be sure that it did the right thing.
Code review comments
They 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.
Advanced Pulling

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 [1]wants to merge 2 commits into Gnucash:future from 0-wiz-0:future

I would locally run this command (with future being checked out and fully up to date with future on code.gnucash.org):

git pull https://github.com/0-wiz-0/Gnucash future

If future on code.gnucash.org has diverged from 0-wiz-0's future branch, this will trigger a merge action, otherwise it would be a fast-forward.

Sidenote
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
  • depending on the complexity:
    • simple PR: check out [target-branch] (future in the example, but can be stable as well for other PR's)
    • complex PR: create [source-branch] based on target-branch
  • 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"
    
Hint
If it asks for a password you might have mistyped something.
  • Additional step for complex PRs: After checking the correctness and potential fixes, merge the source-brancch in the target-branch.

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.

Another approach
is to add "fetch = +refs/pull/*/head:refs/pull/origin/*" to [remote "origin"] in your .git/config.
After a git fetch origin you can i.e.
git checkout -b PR${PRNR} pull/origin/${PRNR}  # ${PRNR}: Number of the pull request
to get a pull request branch based on its number.
(from https://gist.github.com/Chaser324/ce0505fbed06b947d962#checking-out-and-testing-pull-requests)
Pro
This is still possible, after the branch at github.com/"$github-user" was accidently deleted.
Con
It is not possible to push a patch onto github.com/"$github-user"'s PR.
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.

Collaboration

With rare exceptions we don't want to clutter the future 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.

Related Topics

  • 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.

Back to Development Process
  1. Before version 5.0 stable was named maint and future master. Discussionand Announcement