Skip to content

How to contribute code to an existing project

Get the code

If you don't already have a copy of the code for your project, you need to start by cloning the repository.

Before you clone, first, follow the instructions here to generate an SSH key. Then go to to upload your new SSH key to GitLab:

GitLab SSH key settings

Now you can clone your repository using the git@ URL, which will allow you to connect securely to GitLab using SSH. For example, if you were working on this documentation:

git clone

You can find the long URL that you need on the front page of the GitLab project.

Everything starts with an Issue

All new features, or bug fixes start with an issue, which is a document that should accurately describe the problem that needs to be solved. Each issue should describe a single bug or new feature, that should take at most a few days to resolve. If an issue takes longer than that to deal with, or you find new problems as you go along, split the issue up into smaller issues and focus on one at a time.

If there is a Trello board related to the project (or if user stories are kept on a separate site), the relevant Trello card should be linked either in the issue itself or in a comment on the issue page.

Each project repo has its own list of issues, for example, the one for this repository can be found here. Notice the board has special lists for issues that need to be resolved ~"To Do", issues that someone is working on now ~"Doing". You can either drag and drop issues between these boards, or edit the tags on each issue manually, but the effect is the same.

Resolving the issue might require adding new code, tests and/or documentation to the project, fixing existing code or creating a database migration. Hopefully, the issue has been well described and triaged to give you some clues as to how best to resolve it.

To start resolving an issue, you should take the following steps:

  1. Open the issue in GitLab.
  2. Assign yourself to the issue - Assignee should be at the top-right hand corner of the issue page, and there should be a link to assign yourself.
  3. Remove the ~"To Do" tag from the issue and add the ~"Doing" tag, so that everyone knows you are working on this issue (and we don't end up with two people doing the same work!).
  4. Click on Create merge request near the top of the issue page; this creates a new branch in the git repository, and a new page in GitLab where the issue can be discussed.
  5. The target branch for your merge requests should (almost always) be develop.
  6. The source branch will have the same name as your issue title.

A merge request is exactly what it sounds like -- a request that the project maintainer (usually the CTO) should merge your new code or fixes into the code we already have for your project.

Overall workflow

graph TD A[Choose an Issue labelled To Do] --> B[Assign yourself] B --> C[Remove To Do label] C --> D[Add Doing label] D --> E[Create Merge Request] E --> F[Commit to feature branch] F --> F F --> |MR is ready for review| G[Remove **Draft** marker] G --> H[Add Under Review label] H --> I{Assign the CTO to review MR} F --> I I --> |MR passes review| J[Reviewer assigns Bob the Bot to MR] I --> |Respond to review comments|F J --> K[MR is merged]

Working on a feature branch

Next you need the branch that GitLab created when you started the new merge request, we call this a feature branch because it should contain the code for your new feature or bug fix.

On the command line, or in your IDE, fetch the new branch:

$ git fetch -p --all
 * [new branch]      1-create-a-gitlab-merge-request-howto -> origin/1-create-a-gitlab-merge-request-howto
Already up-to-date.
Current branch main is up-to-date.

The -all in git fetch means that git will fetch branches, tags and commits. The -p means prune, so anything that was deleted in GitLab will be deleted in your local repository.

Then switch to the new branch:

$ git checkout 1-create-a-gitlab-merge-request-howto
Branch '1-create-a-gitlab-merge-request-howto' set up to track remote branch '1-create-a-gitlab-merge-request-howto' from 'origin'.
Switched to a new branch '1-create-a-gitlab-merge-request-howto'

How should I work on my feature branch?

As usual with git development, you should work on your branch and commit your work at regular intervals. Make sure you commit and push your code, so that it's sorted on the GitLab servers.

Writing good commit messages

Each commit should be a single change in the code (e.g. a new function with tests, or a new DB migration). Your commit messages should clearly describe what you changed, and it is a good idea to follow the advice in Chris Beam's post. You should try to use good English and turn your spell checker on.

The first line of your commit message should have be no more than 50 characters long. It should summarise the commit and end in a full stop.

The rest of the message should describe the changes in more detail. In particular, you should include any details that will not be obvious from looking at the code.

Here's an example:

Authenticate LDAP user with correct name.
The user name of an LDAP user is not necessarily the first part of their email address. Therefore, we first retrieve the correct username from the server (if the user exists), before authenticating.

How do I know when my work is finished?

Clearly, your code needs to fully resolve the issue it is responding to - i.e. implement a new feature or fix a bug. On top of that, your code should be high quality. In particular, all new code should have unit tests associated with it, and should conform to a relevant coding standard. This should be PSR 2 for PHP, PEP8 for Python, or the equivalent for whatever language you are using.

How you run your unit tests and check your coding style (called linting) will depend on the language you are using.

Only committing working code

If you run unit tests and lints locally, you might sometimes forget to check your code before committing it. Ideally, every commit should be a working point in the history of the code, so it would be preferable to ensure that every commit is fully tested, not just every merge request (which should be tested automatically by GitLab).

Some Beautiful Canoe projects help you to achieve this with git hooks. These are small scripts that are run when a particular git operation (such as committing, or pushing) is performed. If your project has any git hooks, they should be documented in the file in your repository.


Git hooks will assume that you have any necessary lints or unit testing frameworks already installed and set up correctly. Make sure that you read carefully through the file in your repository and follow the instructions there.

As an example, this repository uses a lint to check that the Markdown documentation here follows a set of guidelines. This is checked automatically by GitLab CI, but developers can also choose to check the Markdown each time they commit any changes, and reject any commits that do not pass the lint.

The file hooks/pre-commit contains the git hook itself. Before installing it, you should read through the file and make sure you have installed the relevant dependencies. It would also be wise to try running the file -- if it does not work correctly on your machine, you won't be able to commit anything once it is installed!

When you are ready, run the install script:



The hook install script may not be cross-platform. If you need to install the hooks manually, either copy them directly into the .git/hooks/ directory in your repository, or create symbolic links.

What do I do when my feature branch is ready for review?

When you think you have finished working on your issue, you need someone (usually the CTO) to review it. Please do not do this unless your branch passes the GitLab CI pipeline -- we only merge branches that pass CI! These are three steps you should take to make that happen:

Mark the MR as ready

Remove the Draft marker on the merge request by clicking the Mark as ready button on the merge request page.

Add the ~"Under Review" label

Add the ~"Under Review" label to your merge request and the issue it resolves. This helps us to keep track of how long our review queue is.

Assign a reviewer

At the top-right of the merge request page you will see a link named Assignee. Unless you have been told otherwise, this should be the CTO.


Assignees can be a bit confusing, but remember you are assigned to the issue, and the reviewer is assigned to the merge request.

When you have assigned a reviewer and removed the Draft marker, your reviewer will read through your code and make comments on the merge request page. Some of these comments might be requests for you to make further changes to your work.


The person who reviews your merge request should NEVER have authored any commits on your feature branch. If for some reason a reviewer needs to contribute to your branch, they should re-assign the merge request to a new reviewer.

What if my reviewer requests more changes?

Once your reviewer has read through your commits, they should write a comment summarising their feedback. Usually, your reviewer will ask for further changes. These should just be added to the branch as further commits. When you feel you have resolved all the problems raised in the discussion, it is your responsibility to tell the reviewer. The easiest way to do this is just to add a comment to the discussion, ideally AT-ing the reviewer (i.e. mentioning the CTO) when you do.

What if my feature branch is not up to date with the target branch?

Sometimes another feature branch will be merged into your target branch (e.g. develop) before your merge request has been completed. In this case, before your MR can be merged, you will need to bring it up to date with the target branch.

This should be the last thing you do before the MR is completed. If you bring your branch up to date early, you will confuse the reviewer who is following your commits. If you think there is a good reason for doing this before the reviewing process has finished, you must tell the reviewer in the comments of your MR.

To bring your branch up to date with the target branch (develop in this example), do this:

git pull --rebase origin develop

You will then have to fix any merge conflict that arise. Once you have finished you should force-push to your branch:

git push -f origin 1-create-a-gitlab-merge-request-howto


DO NOT try to bring an MR up to date using the GitLab user interface, the merge buttons do something very different to git pull --rebase origin develop.

What happens when my branch is merged?

To merge your branch, your reviewer will assign it to the GitLab user @bc-bot (Bob The Beautiful Canoe Robot). Bob the Bot will make some changes to your commit messages (to make it clear which MR they are part of), and perform the merge.

Why do we use Bob for merging MRs? Two main reasons: firstly, if GitLab experiences problems Bob will keep on trying to merge your MR. This means that a member of staff doesn't have to constantly check back on their MRs until GitLab is up and running smoothly again. Secondly, if a branch is behind main, @bc-bot will try to update it. If it's possible to update the branch automatically, and the MR passes its pipeline tests, Bob will merge the MR. Again, this saves us effort, especially when several developers are working on the same project and trying to merge to the same target branch. Sometimes though, Bob will not be able to merge an MR, in which case he will re-assign the MR to the author, and ask the author to fix the problem.


Note that Bob the Bot does not merge code between Friday afternoon and Monday morning. This is to avoid Beautiful Canoe staff working over the weekend. If your merge request is assigned to @bc-bot on late Friday afternoon, you will have to wait until Monday for it to be merged.

You can read more about how Bob works here.

Once your MR has been merged, both the MR and its original issue will be marked as closed. Your feature branch should also have been deleted from the GitLab repo (please tell your reviewer if this hasn't happened). You will now need to update your git clone of the repo, fetching changes and deleting old branches:

$ git checkout develop

# Fetch everything that changed on GitLab
$ git fetch -p --all
 - [deleted]         (none)     -> origin/1-create-a-gitlab-merge-request-howto

$ git branch
* develop

# Delete the feature branch we just finished with
$ git branch -d 1-create-a-gitlab-merge-request-howto

# List available branches
$ git branch
* develop

# Pull new changes added to develop
$ git pull origin develop
 * branch            develop    -> FETCH_HEAD
   e1125a7..ccde6b5  develop    -> origin/develop
Updating e1125a7..ccde6b5
Fast-forward             | 12 +++----

Further reading

There are a number of workflows that are commercially used with Git repositories. These include Git flow, GitHub flow and GitLab flow. The differences between these are relatively subtle, and our Beautiful Canoe workflow is slightly different again. However, you may want to read around the different alternatives, to learn more about the sort of techniques that you might see in industry.