Definition of the swisstopo git
workflow used in github repositories in order to keep the history as clean as possible.
- Goal
- Branch Model
- Long term development:
develop-DESCRIPTION
- Pull Request Rules
- Git Workflows
- New release
- Merge Conflict
- GIT Configuration
- Github repository Configuration
- References
The goal of the following rules and workflow is to avoid such git history
Which can end up quite messy
But to have an history like this
Which is, when we avoid hotfix
, much easier to read and understand.
We follow the git flow as in the picture below:
This flow is an adaptation of the original Git Flow with some ideas from Github Flow and Gitlab Flow.
The main branch is master
and the branches for development are develop
and develop-YYYY-MM-DD
(see Milestone Versioning.
- Everything in
master
,develop
anddevelop-YYYY-MM-DD
branch has production quality - Directly pushing to
master
,develop
ordevelop-YYYY-MM-DD
is forbidden and should be protected by github branch rule master
,develop
anddevelop-YYYY-MM-DD
are SHARED branchespush --force
on shared branches is FORBIDDEN- Code on
master
is deployed on PROD and INT - Code on
develop
ordevelop-YYYY-MM-DD
is deployed on DEV - New features and bug fixes are done on PERSONAL branches (see below for naming conventions) and merged in
develop
or indevelop-YYYY-MM-DD
- Personal branches are owned by the creator and only the owner is allowed to push to it ! This allow the uses of
push --force
on those branches. - Hot fixe should be avoided, if not avoidable it must be small changes and directly merged into
master
,develop
ordevelop-YYYY-MM-DD
The naming convention below is important for the github actions to work properly !
Branch | Description |
---|---|
data-JIRA-* |
Personal branch to be merged by PR into develop-YYYY-MM-DD . This branch SHOULD have a JIRA ticket number and optionally a very short title at the end. This branch contains data integration related work. |
feat-JIRA-* , feature-JIRA-* |
Personal branch to be merged by PR into develop or develop-YYYY-MM-DD . This branch SHOULD have a JIRA ticket number and optionally a very short title at the end. This branch contains non data integration related work that should be done for the next release. |
bug-JIRA-* , bugfix-JIRA-* |
Personal branch to be merged by PR into develop or develop-YYYY-MM-DD . This branch SHOULD have a JIRA ticket number and optionally a very short title at the end. This branch contains bugfix related work that should be done for the next release. |
hotfix-JIRA-* |
Personal branch to be merged by PR directly into master and will be deployed as hot fix. Note here the JIRA ticket might be optional if there is no JIRA ticket related to the bug fix. |
NOTES:
- Prefix in branch names are important in order to set the correct PR label for release note categorization!
- JIRA ticket number in branch is important in order to link the branch to the JIRA ticket !
- Git commit should also have the JIRA ticket number in the title for the linking !
In case of a long term development, we should avoid working weeks or even worse months long on a single PR
creating at the end a huge PR to review. Review of huge PR is not efficient and often of bad review quality
(missing important points). To avoid this and still keep the branch rules defined above (master
and
develop
branches have production and working quality codes), we can create a third shared branch;
develop-DESCRIPTION
where DESCRIPTION
is a meaningful short description that can be easily understood (for example develop-refactor-drawing
, develop-migration-frankfurt
).
This branch must then follow these rules:
- Must be created from
develop
- for milestone workflow repository (e.g.
mf-chsdi3
) then we have two use cases- The development is done within a few to several weeks and is to be completed before the end of the current milestone. The work is data integration related.
develop-DESCRIPTION
is created fromdevelop-YYYY-MM-DD
branchdevelop-DESCRIPTION
is to be merged intodevelop-YYYY-MM-DD
branch at the end.
- The development spanned accross several milestones and is not really data integration related
develop-DESCRIPTION
is created frommaster
develop-DESCRIPTION
is merged intomaster
at the end
- The development is done within a few to several weeks and is to be completed before the end of the current milestone. The work is data integration related.
- for milestone workflow repository (e.g.
develop-DESCRIPTION
is a shared branch where several developer can work on it and MUST have github branch rule set accordingly.- Directly pushing to
develop-DESCRIPTION
is forbidden and should be protected by github branch rule - All PRs to
develop-DESCRIPTION
must be peer reviewed before merging (protected by github rule)
- Directly pushing to
- New features/bug fixes are done on PERSONAL branches (see below for naming conventions) and merged into
develop-DESCRIPTION
via reviewed PRs. - Personal branches are owned by the creator and only the owner is allowed to push to it ! This allow the uses of
push --force
on those branches. - PRs to
develop-DESCRIPTION
code might not be working and might make the unit test failing, but still needs to have productive/clean code. - TODO in
develop-DESCRIPTION
PRs are allowed. - All other PR rules defined below in Pull Request Rules are still valid (except of the two points mentioned just above)
develop-DESCRIPTION
branch needs to be regularly updated from its upstream branch; create a PR to mergedevelop
intodevelop-DESCRIPTION
- Once
develop-DESCRIPTION
has reached a fully working productive state, it can be merged back into its upstream branch; create a PR to mergedevelop-DESCRIPTION
intodevelop
and once merged deletedevelop-DESCRIPTION
-
Pull requests should only be created if the changes in the
feature|bugfix|hotfix
branch is ready to be discussed/reviewed/merged. Exception to the rules are PR for RFC (see PR for Request For Comment (RFC)). -
A PR should be of production quality
-
A PR has a proper title. The title MUST contain the JIRA related ticket number if any (
PB-9999: ...
). -
A PR Title should reflect the changes and be written in past tense. Title is used to generate the Release Note !
-
A PR is only assigned for review when it's finished and not WIP anymore, all commits must be ready for review (see below)
-
A PR contains atomic and well named commits:
-
Each commit should have a comment in the following forms
<jira-issue-id>: Title (should not be more than 100 chars) Description of the issue being fixed by the commit. Eventually how the issue could be reproduced. Description of the solution to the issue that is being fixed.
-
if you have too many commits in your PR, squash them before assigning the PR for review
-
-
A PR addresses a well described and well documented issue
-
A PR describes the changes that are introduced and mentions possible side-effects for testing
-
A PR describes the necessary steps to undertake before merging (infrastructure, data, varnish, etc.)
-
A PR provides a test link - and if that's not possible describes how it can be tested
-
PR must be peer-reviewed (unless changes are trivial). This applies to everything under version control (code, scripts, config, SQL,...). Try to review quickly if your review is requested.
-
EVERY Developer is responsible to periodically checks his review requests (using email notification and/or the github Pull Request page) and to answer them ASAP, in order to not slow down development.
-
PR must be merged with merge commits. This keeps the original commit hashes, adds a dedicated merge-commit and makes it easier to figure out which commits have been merged in which branches (no
fast forward
merge). -
Avoid changing commits after review (avoid squash, split or rewrite), do new commit to apply the requested changes by the reviewer.
-
PR must be up to date before merge, do a
git rebase
before merging.git fetch origin git rebase origin/develop # or origin/master git push --force origin PR_BRANCH
-
Don't use the
Update Branch
Github button, use git CLI instead (see above). Alternatively you can use theUpdate with rebase
Github button -
Work is considered done, if a PR is merged (not when it's created)
PR can be used for starting a discussion as RFC. In this case the first rule can be ignored, but you need then to follow these ones:
-
PRs for RFC must have
RFC
label and must be marked asDraft
. -
Git commit don't requires propers message as the PR is in draft mode
-
Once the RFC has ended, there is the following two possible flow:
-
The PR is closed with a comment. Nothing gets merged!
-
The PR is ready for review.
- This imply to first remove
RFC
label - Then make sure that the PR follows the Pull Request Rules above
- Finally remove it from
Draft
mode by clicking onReady for Review
button
- This imply to first remove
-
PR could be used to test the code on CodeBuild (usually only needed when setting up CodeBuild):
-
PRs for WIP must have
WIP
label and must be marked asDraft
. -
Git commit don't requires propers message as the PR is in draft mode
-
Once the WIP has ended, there is the following two possible flow:
-
The PR is closed with a comment. Nothing gets merged!
-
The PR is ready for review.
- This imply to first remove
WIP
label - Then make sure that the PR follows the Pull Request Rules above
- Finally remove it from
Draft
mode by clicking onReady for Review
button
- This imply to first remove
-
This workflow refers to SemVer versioning, for milestone simply replace develop
by develop-YYYY-MM-DD
.
-
Update the
develop
branchgit checkout develop git pull # git pull origin develop
-
Create and checkout your personal branch named according to the convention.
git checkout -b PRIVATE_BRANCH # git branch PRIVATE_BRANCH; git checkout PRIVATE_BRANCH
-
Do your work and push it to the server
git add . git commit -m "did something" git push origin PRIVATE_BRANCH # NEVER EVER DO `git push` always specify the destination `origin` and source
-
Update first your personal branch
git checkout PRIVATE_BRANCH git fetch origin develop:develop # git fetch origin master:master git rebase origin/develop # or for master PR git rebase origin/master
-
Eventually re-organize, squash or rewrites your commits to have them production ready
git rebase -i origin/develop # or git rebase -i origin/master # then push the new commits git push --force origin PERSONAL_BRANCH # force push on personal branch is allowed
-
Login into Github and navigate to the repo in order to create the PR (follow the Pull Request Rules above)
-
Assign one or more reviewer
Once a PR has been created, some modification might be requested by peers (reviewer).
- Create new commits and push them back to your personal branch (PR branch)
- Eventually update the PR branch with
git rebase origin/develop|origin/master
- Re-request a review of your changes
Once a PR has been approved do as follow
-
Make sure that the PR is up to date
git fetch origin develop:develop git rebase -i origin/develop # or git rebase -i origin/master # then push the new commits git push --force origin PRIVATE_BRANCH
-
Then merge the PR to
develop
ormaster
. This should be done from Github and not from the CLI -
Finally do some clean up actions: delete your local PR branch as well as the remote PR branch (if not automatically done)
git branch -d PRIVATE_BRANCH
When trying to merge a PR, conflict might occur. There is 2 type of conflicts that needs to be dealt differently.
When merging a personal branch into a shared branch (e.g. feat-my-feature
into develop
), we should
never have conflict as the head branch should be always rebased on top of the base branch. Due to this
conflict always happens during the rebase and needs to be fixed during the rebase step on the personal branch.
When merging two shared branches, conflict might occurs and we can't directly fix them on a shared branch has we have a PR policy.
In this case we should never have any conflict because should always keep develop*
up to date by
merging master
into develop*
(this is only needed when hotfixes have been merged into master
).
When hotfixes have been merged into master
then need to be added as well on the develop*
branch.
For this we create a PR to merge master
into develop*
.
This branch is out-of-date with the base branch
warning. Due to the nature of
our git flow master
branch can be out of date based on develop
and in this special use case admin
are allow to bypass the branch protection. See github.com/orgs/geoadmin/teams/pp-bgdi-admin
to see who is currently admin.
In this case conflict might occur ! To solve them procede as follow:
-
First open a PR to merge
master
intodevelop
ordevelop-YYYY-MM-DD
-
Then if the PR can't be merge do to conflict, checkout both branch locally (make sure that both branch are up to date with their origin)
git checkout master git pull git checkout develop git pull
-
Then manually merge
master
intodevelop
git merge master
-
Solve the merge conflict using the merge tool (at best with Beyond Compare)
git mergetool
-
Once all conflict have been resolved, commit the mergeconflict changes, it is a best practice to put the files that had conflict in the merge commit message. For this simply uncomment the conflicts line in the automatic commit message.
git commit
-
Finally, push the merge. Before this make sure that the PR open in step 1. has been approved, otherwise you won't be able to merge !
git push origin develop
Follow the same step as in Merging master
into develop
or develop-YYYY-MM-DD
In order to have a proper git history, each developer MUST HAVE the following git configuration
$ git config --global --list
...
user.name=<developer-full-name>
user.email=<developer-email>
merge.ff=false
pull.rebase=true
...
To edit the config do:
git config --global --add user.name <full-name>
git config --global --add user.email <email>
git config --global --add merge.ff false
git config --global --add pull.rebase true
# or
$ git config --global --edit
...
[user]
name = <full-name>
email = <email>
[merge]
ff = false
...
This ensure that a commit has a proper author and that the default behavior for merge is a non fast forward.
- Each github repo MUST BE configured to enforce PR review.
- Each github repo MUST DISALLOW the PR Merge if the PR is not up to date.
- Each github repo configuration MUST BE managed by Terraform, see geoadmin/infra-terraform-github-bgdi
Here below are the reference list for the flow: