Working with branches and forks

Where are the branches?

We have split each of the Dalton and LSDalton repositories into two, a public repository and a private repository. So instead of two repositories we now have four: two public (containing the master and release branches), and two private repositories (containing all other branches):

https://gitlab.com/dalton/dalton/
https://gitlab.com/dalton/dalton-private/
https://gitlab.com/dalton/lsdalton/
https://gitlab.com/dalton/lsdalton-private/

The master branch

The master branches on the public repositories are the main development lines. Features should be developed on separate feature branches on the private repositories. The semantics of the master branch is that everything that is committed or merged to master is ready to be released in an upcoming release.

Release branches

Release branches are located on the public repositories, and are labeled release/2013, release/2015, etc. They branch from master once at feature freeze. They collect patches. All commits to release branches can be merged to master in principle at any moment. We never merge branches to release branches (except when accepting merge requests).

release/2013 branch becomes frozen once Dalton 2015 is released. release/2015 branch becomes frozen once Dalton 2016 is released. And so on.

How to make changes to master or the release branches

Never push changes directly to https://gitlab.com/dalton/dalton/ or https://gitlab.com/dalton/lsdalton/. Instead do this:

  1. Create a fork.
  2. Clone the fork.
  3. Create a feature branch. Never commit any changes to master or a release branch.
  4. Commit to the feature branch.
  5. Push the feature branch to the fork.
  6. Submit a merge request. You can mark the feature branch to be automatically deleted once the merge request is accepted. make sure that you do not forget any of the following points:
  • Do not submit unfinished work.
  • Be aware that everything on master will be part of the next major release.
  • Describe your change in the CHANGELOG.
  • Commits should have the right size (not too small, not too large) - otherwise squash or split changes.
  • Commit messages should be clear.
  • Commits should be self contained
  • Test new code.
  • Comment new code.
  • Document new code.
  • When fixing an issue, autoclose the issue with the commit message.

All commits to the master branch should be self-contained, eg. fix a bug or add a new feature, the commit message should clearly state what is achieved by the commit, and each commit should compile and run through the test suite. Long-term developments typically have several commits, many of which break compilation or test cases, and merging such developments directly will both make the git history ugly, and break functionality like ``git bisect’‘. Such developments should therefore be squashed into one or a few commits.

Squashing

Assume you are working with two remote repositories “origin” and “upstream” (see how below). You have developed a new feature branch “my_messy_branch” on “origin” and incorporated the changes from “upstream” “master” into it, and would like to merge your changes back to “upstream” “master”.

First, make a local copy of your branch “my_messy_branch”:

$ git branch -b my_clean_branch

Second, rebase ``my_clean_branch’’ with respect to “upstream” “master”:

$ git rebase upstream master

Third, make a ``soft’’ ``reset’‘

$ git reset –soft upstream master

This step removes all local commits, but leaves the code unchanged. This can be verified with a ``git status’‘.

Fourth, make a commit of all the changes from “my_messy_branch” into one single commit on “my_clean_branch”, by a regular ``git commit’‘, followed by a ``git push origin my_clean_branch’‘, and a subsequent merge request on gitlab.

Where to keep feature branches

You can either develop them on one of the private repositories (discouraged), or on your fork (encouraged). The fork can be either private or public.

How to update feature branches

You have probably cloned from your fork (good!) but from time to time you wish to update your feature branch(es) with changes on master.

First make sure that your clone is really cloned from your fork:

$ git remote -v

The remote origin should now point to your fork - here is an example:

origin git@gitlab.com:user/dalton.git (fetch)
origin git@gitlab.com:user/dalton.git (push)

We encourage you to regard the master branch as read-only and discourage you from making any changes to the master branch directly.

To update your forked master branch and your feature branches first add the central repository as an additional remote. You can call it for instance “upstream”:

$ git remote add upstream git@gitlab.com:dalton/dalton.git

Verify that it worked:

$ git remote -v

origin git@gitlab.com:user/dalton.git (fetch)
origin git@gitlab.com:user/dalton.git (push)
upstream git@gitlab.com:dalton/dalton.git (fetch)
upstream git@gitlab.com:dalton/dalton.git (push)

Good! Now you can fetch changes from upstream and merge master to your feature branch:

$ git fetch upstream
$ git checkout my-feature-branch
$ git merge upstream/master
$ git push origin my-feature-branch

How to update your fork

A fork is a clone. It will not update itself. To update your fork you need to pull changes from the upstream repository and push them to your fork.

You can do this either by adding an alias to a remote:

$ git remote add upstream git@gitlab.com:dalton/dalton.git
$ git fetch upstream
$ git checkout master
$ git merge upstream/master
$ git push origin master

Once you realize that “origin” and “upstream” are nothing more than aliases to web URIs you can fetch and push changes directly without defining new remotes:

$ git pull git@gitlab.com:dalton/dalton.git master
$ git push git@gitlab.com:user/dalton.git master

For other branches it works exactly the same way. For Git, all branches are equivalent. It is only convention to attach master a special meaning.