Commit 41a5d0e0 authored by Stephen Wade's avatar Stephen Wade Committed by Evan Read

Rewrite GitLab Flow doc

parent 69c19b39
...@@ -2,314 +2,324 @@ ...@@ -2,314 +2,324 @@
# Introduction to GitLab Flow # Introduction to GitLab Flow
Version management with git makes branching and merging much easier than older versioning systems such as SVN. Git allows a wide variety of branching strategies and workflows.
This allows a wide variety of branching strategies and workflows. Because of this, many organizations end up with workflows that are too complicated, not clearly defined, or not integrated with issue tracking systems.
Almost all of these are an improvement over the methods used before git. Therefore, we propose GitLab flow as a clearly defined set of best practices.
But many organizations end up with a workflow that is not clearly defined, overly complex or not integrated with issue tracking systems. It combines [feature-driven development](https://en.wikipedia.org/wiki/Feature-driven_development) and [feature branches](https://martinfowler.com/bliki/FeatureBranch.html) with issue tracking.
Therefore we propose the GitLab flow as clearly defined set of best practices.
It combines [feature driven development](https://en.wikipedia.org/wiki/Feature-driven_development) and [feature branches](http://martinfowler.com/bliki/FeatureBranch.html) with issue tracking.
Organizations coming to git from other version control systems frequently find it hard to develop an effective workflow. Organizations coming to Git from other version control systems frequently find it hard to develop a productive workflow.
This article describes the GitLab flow that integrates the git workflow with an issue tracking system. This article describes GitLab flow, which integrates the Git workflow with an issue tracking system.
It offers a simple, transparent and effective way to work with git. It offers a simple, transparent, and effective way to work with Git.
![Four stages (working copy, index, local repo, remote repo) and three steps between them](four_stages.png) ![Four stages (working copy, index, local repo, remote repo) and three steps between them](four_stages.png)
When converting to git you have to get used to the fact that there are three steps before a commit is shared with colleagues. When converting to Git, you have to get used to the fact that it takes three steps to share a commit with colleagues.
Most version control systems have only one step, committing from the working copy to a shared server. Most version control systems have only one step: committing from the working copy to a shared server.
In git you add files from the working copy to the staging area. After that you commit them to the local repo. In Git, you add files from the working copy to the staging area. After that, you commit them to your local repo.
The third step is pushing to a shared remote repository. The third step is pushing to a shared remote repository.
After getting used to these three steps the branching model becomes the challenge. After getting used to these three steps, the next challenge is the branching model.
![Multiple long running branches and merging in all directions](messy_flow.png) ![Multiple long-running branches and merging in all directions](messy_flow.png)
Since many organizations new to git have no conventions how to work with it, it can quickly become a mess. Since many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
The biggest problem they run into is that many long running branches that each contain part of the changes are around. The biggest problem is that many long-running branches emerge that all contain part of the changes.
People have a hard time figuring out which branch they should develop on or deploy to production. People have a hard time figuring out which branch has the latest code, or which branch to deploy to production.
Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html). Frequently, the reaction to this problem is to adopt a standardized pattern such as [Git flow](https://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html).
We think there is still room for improvement and will detail a set of practices we call GitLab flow. We think there is still room for improvement. In this document, we describe a set of practices we call GitLab flow.
## Git flow and its problems ## Git flow and its problems
![Git Flow timeline by Vincent Driessen, used with permission](gitdashflow.png) ![Git Flow timeline by Vincent Driessen, used with permission](gitdashflow.png)
Git flow was one of the first proposals to use git branches and it has gotten a lot of attention. Git flow was one of the first proposals to use Git branches, and it has received a lot of attention.
It advocates a master branch and a separate develop branch as well as supporting branches for features, releases and hotfixes. It suggests a `master` branch and a separate `develop` branch, as well as supporting branches for features, releases, and hotfixes.
The development happens on the develop branch, moves to a release branch and is finally merged into the master branch. The development happens on the `develop` branch, moves to a release branch, and is finally merged into the `master` branch.
Git flow is a well defined standard but its complexity introduces two problems.
The first problem is that developers must use the develop branch and not master, master is reserved for code that is released to production. Git flow is a well-defined standard, but its complexity introduces two problems.
It is a convention to call your default branch master and to mostly branch from and merge to this. The first problem is that developers must use the `develop` branch and not `master`. `master` is reserved for code that is released to production.
Since most tools automatically make the master branch the default one and display that one by default it is annoying to have to switch to another one. It is a convention to call your default branch `master` and to mostly branch from and merge to this.
The second problem of git flow is the complexity introduced by the hotfix and release branches. Since most tools automatically use the `master` branch as the default, it is annoying to have to switch to another branch.
The second problem of Git flow is the complexity introduced by the hotfix and release branches.
These branches can be a good idea for some organizations but are overkill for the vast majority of them. These branches can be a good idea for some organizations but are overkill for the vast majority of them.
Nowadays most organizations practice continuous delivery which means that your default branch can be deployed. Nowadays, most organizations practice continuous delivery, which means that your default branch can be deployed.
This means that hotfix and release branches can be prevented including all the ceremony they introduce. Continuous delivery removes the need for hotfix and release branches, including all the ceremony they introduce.
An example of this ceremony is the merging back of release branches. An example of this ceremony is the merging back of release branches.
Though specialized tools do exist to solve this, they require documentation and add complexity. Though specialized tools do exist to solve this, they require documentation and add complexity.
Frequently developers make a mistake and for example changes are only merged into master and not into the develop branch. Frequently, developers make mistakes such as merging changes only into `master` and not into the `develop` branch.
The root cause of these errors is that git flow is too complex for most of the use cases. The reason for these errors is that Git flow is too complicated for most use cases.
And doing releases doesn't automatically mean also doing hotfixes. For example, many projects do releases but don't need to do hotfixes.
## GitHub flow as a simpler alternative ## GitHub flow as a simpler alternative
![Master branch with feature branches merged in](github_flow.png) ![Master branch with feature branches merged in](github_flow.png)
In reaction to git flow a simpler alternative was detailed, [GitHub flow](https://guides.github.com/introduction/flow/index.html). In reaction to Git flow, GitHub created a simpler alternative.
This flow has only feature branches and a master branch. [GitHub flow](https://guides.github.com/introduction/flow/index.html) has only feature branches and a `master` branch.
This is very simple and clean, many organizations have adopted it with great success. This flow is clean and straightforward, and many organizations have adopted it with great success.
Atlassian recommends [a similar strategy](http://blogs.atlassian.com/2014/01/simple-git-workflow-simple/) although they rebase feature branches. Atlassian recommends [a similar strategy](https://www.atlassian.com/blog/archives/simple-git-workflow-simple), although they rebase feature branches.
Merging everything into the master branch and deploying often means you minimize the amount of code in 'inventory' which is in line with the lean and continuous delivery best practices. Merging everything into the `master` branch and frequently deploying means you minimize the amount of unreleased code, which is in line with lean and continuous delivery best practices.
But this flow still leaves a lot of questions unanswered regarding deployments, environments, releases and integrations with issues. However, this flow still leaves a lot of questions unanswered regarding deployments, environments, releases, and integrations with issues.
With GitLab flow we offer additional guidance for these questions. With GitLab flow, we offer additional guidance for these questions.
## Production branch with GitLab flow ## Production branch with GitLab flow
![Master branch and production branch with arrow that indicate deployments](production_branch.png) ![Master branch and production branch with an arrow that indicates a deployment](production_branch.png)
GitHub flow does assume you are able to deploy to production every time you merge a feature branch. GitHub flow assumes you can deploy to production every time you merge a feature branch.
This is possible for e.g. SaaS applications, but there are many cases where this is not possible. While this is possible in some cases, such as SaaS applications, there are many cases where this is not possible.
One would be a situation where you are not in control of the exact release moment, for example an iOS application that needs to pass App Store validation. One case is where you don't control the timing of a release, for example, an iOS application that is released when it passes App Store validation.
Another example is when you have deployment windows (workdays from 10am to 4pm when the operations team is at full capacity) but you also merge code at other times. Another case is when you have deployment windows — for example, workdays from 10 AM to 4 PM when the operations team is at full capacity — but you also merge code at other times.
In these cases you can make a production branch that reflects the deployed code. In these cases, you can make a production branch that reflects the deployed code.
You can deploy a new version by merging in master to the production branch. You can deploy a new version by merging `master` into the production branch.
If you need to know what code is in production you can just checkout the production branch to see. If you need to know what code is in production, you can just checkout the production branch to see.
The approximate time of deployment is easily visible as the merge commit in the version control system. The approximate time of deployment is easily visible as the merge commit in the version control system.
This time is pretty accurate if you automatically deploy your production branch. This time is pretty accurate if you automatically deploy your production branch.
If you need a more exact time you can have your deployment script create a tag on each deployment. If you need a more exact time, you can have your deployment script create a tag on each deployment.
This flow prevents the overhead of releasing, tagging and merging that is common to git flow. This flow prevents the overhead of releasing, tagging, and merging that happens with Git flow.
## Environment branches with GitLab flow ## Environment branches with GitLab flow
![Multiple branches with the code cascading from one to another](environment_branches.png) ![Multiple branches with the code cascading from one to another](environment_branches.png)
It might be a good idea to have an environment that is automatically updated to the master branch. It might be a good idea to have an environment that is automatically updated to the `master` branch.
Only in this case, the name of this environment might differ from the branch name. Only, in this case, the name of this environment might differ from the branch name.
Suppose you have a staging environment, a pre-production environment and a production environment. Suppose you have a staging environment, a pre-production environment, and a production environment.
In this case the master branch is deployed on staging. When someone wants to deploy to pre-production they create a merge request from the master branch to the pre-production branch. In this case, deploy the `master` branch to staging.
And going live with code happens by merging the pre-production branch into the production branch. To deploy to pre-production, create a merge request from the `master` branch to the pre-production branch.
This workflow where commits only flow downstream ensures that everything has been tested on all environments. Go live by merging the pre-production branch into the production branch.
If you need to cherry-pick a commit with a hotfix it is common to develop it on a feature branch and merge it into master with a merge request, do not delete the feature branch. This workflow, where commits only flow downstream, ensures that everything is tested in all environments.
If master is good to go (it should be if you are practicing [continuous delivery](http://martinfowler.com/bliki/ContinuousDelivery.html)) you then merge it to the other branches. If you need to cherry-pick a commit with a hotfix, it is common to develop it on a feature branch and merge it into `master` with a merge request.
If this is not possible because more manual testing is required you can send merge requests from the feature branch to the downstream branches. In this case, do not delete the feature branch yet.
If `master` passes automatic testing, you then merge the feature branch into the other branches.
If this is not possible because more manual testing is required, you can send merge requests from the feature branch to the downstream branches.
## Release branches with GitLab flow ## Release branches with GitLab flow
![Master and multiple release branches that vary in length with cherry-picks from master](release_branches.png) ![Master and multiple release branches that vary in length with cherry-picks from master](release_branches.png)
Only in case you need to release software to the outside world you need to work with release branches. You only need to work with release branches if you need to release software to the outside world.
In this case, each branch contains a minor version (2-3-stable, 2-4-stable, etc.). In this case, each branch contains a minor version, for example, 2-3-stable, 2-4-stable, etc.
The stable branch uses master as a starting point and is created as late as possible. Create stable branches using `master` as a starting point, and branch as late as possible.
By branching as late as possible you minimize the time you have to apply bug fixes to multiple branches. By doing this, you minimize the length of time during which you have to apply bug fixes to multiple branches.
After a release branch is announced, only serious bug fixes are included in the release branch. After announcing a release branch, only add serious bug fixes to the branch.
If possible these bug fixes are first merged into master and then cherry-picked into the release branch. If possible, first merge these bug fixes into `master`, and then cherry-pick them into the release branch.
This way you can't forget to cherry-pick them into master and encounter the same bug on subsequent releases. If you start by merging into the release branch, you might forget to cherry-pick them into `master`, and then you'd encounter the same bug in subsequent releases.
This is called an 'upstream first' policy that is also practiced by [Google](https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first) and [Red Hat](https://www.redhat.com/about/news/archive/2013/5/a-community-for-using-openstack-with-red-hat-rdo). Merging into `master` and then cherry-picking into release is called an "upstream first" policy, which is also practiced by [Google](https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first) and [Red Hat](https://www.redhat.com/en/blog/a-community-for-using-openstack-with-red-hat-rdo).
Every time a bug-fix is included in a release branch the patch version is raised (to comply with [Semantic Versioning](http://semver.org/)) by setting a new tag. Every time you include a bug fix in a release branch, increase the patch version (to comply with [Semantic Versioning](https://semver.org/)) by setting a new tag.
Some projects also have a stable branch that points to the same commit as the latest released branch. Some projects also have a stable branch that points to the same commit as the latest released branch.
In this flow it is not common to have a production branch (or git flow master branch). In this flow, it is not common to have a production branch (or Git flow `master` branch).
## Merge/pull requests with GitLab flow ## Merge/pull requests with GitLab flow
![Merge request with line comments](mr_inline_comments.png) ![Merge request with inline comments](mr_inline_comments.png)
Merge or pull requests are created in a git management application and ask an assigned person to merge two branches. Merge or pull requests are created in a Git management application. They ask an assigned person to merge two branches.
Tools such as GitHub and Bitbucket choose the name pull request since the first manual action would be to pull the feature branch. Tools such as GitHub and Bitbucket choose the name "pull request" since the first manual action is to pull the feature branch.
Tools such as GitLab and others choose the name merge request since that is the final action that is requested of the assignee. Tools such as GitLab and others choose the name "merge request" since the final action is to merge the feature branch.
In this article we'll refer to them as merge requests. In this article, we'll refer to them as merge requests.
If you work on a feature branch for more than a few hours it is good to share the intermediate result with the rest of the team. If you work on a feature branch for more than a few hours, it is good to share the intermediate result with the rest of the team.
This can be done by creating a merge request without assigning it to anyone, instead you mention people in the description or a comment (/cc @mark @susan). To do this, create a merge request without assigning it to anyone.
This means it is not ready to be merged but feedback is welcome. Instead, mention people in the description or a comment, for example, "/cc @mark @susan."
This indicates that the merge request is not ready to be merged yet, but feedback is welcome.
Your team members can comment on the merge request in general or on specific lines with line comments. Your team members can comment on the merge request in general or on specific lines with line comments.
The merge requests serves as a code review tool and no separate tools such as Gerrit and reviewboard should be needed. The merge request serves as a code review tool, and no separate code review tools should be needed.
If the review reveals shortcomings anyone can commit and push a fix. If the review reveals shortcomings, anyone can commit and push a fix.
Commonly the person to do this is the creator of the merge/pull request. Usually, the person to do this is the creator of the merge request.
The diff in the merge/pull requests automatically updates when new commits are pushed on the branch. The diff in the merge request automatically updates when new commits are pushed to the branch.
When you are ready for your feature branch to be merged, assign the merge request to the person who knows most about the codebase you are changing.
Also, mention any other people from whom you would like feedback.
After the assigned person feels comfortable with the result, they can merge the branch.
If the assigned person does not feel comfortable, they can request more changes or close the merge request without merging.
In GitLab, it is common to protect the long-lived branches, e.g., the `master` branch, so that [most developers can't modify them](../permissions/permissions.md).
So, if you want to merge into a protected branch, assign your merge request to someone with maintainer permissions.
When you feel comfortable with it to be merged you assign it to the person that knows most about the codebase you are changing and mention any other people you would like feedback from. After you merge a feature branch, you should remove it from the source control software.
There is room for more feedback and after the assigned person feels comfortable with the result the branch is merged. In GitLab, you can do this when merging.
If the assigned person does not feel comfortable they can close the merge request without merging. Removing finished branches ensures that the list of branches shows only work in progress.
It also ensures that if someone reopens the issue, they can use the same branch name without causing problems.
In GitLab it is common to protect the long-lived branches (e.g. the master branch) so that normal developers [can't modify these protected branches](http://docs.gitlab.com/ce/permissions/permissions.html). NOTE: **Note:**
So if you want to merge it into a protected branch you assign it to someone with maintainer authorizations. When you reopen an issue you need to create a new merge request.
![Remove checkbox for branch in merge requests](remove_checkbox.png)
## Issue tracking with GitLab flow ## Issue tracking with GitLab flow
![Merge request with the branch name 15-require-a-password-to-change-it and assignee field shown](merge_request.png) ![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](merge_request.png)
GitLab flow is a way to make the relation between the code and the issue tracker more transparent. GitLab flow is a way to make the relation between the code and the issue tracker more transparent.
Any significant change to the code should start with an issue where the goal is described. Any significant change to the code should start with an issue that describes the goal.
Having a reason for every code change is important to inform everyone on the team and to help people keep the scope of a feature branch small. Having a reason for every code change helps to inform the rest of the team and to keep the scope of a feature branch small.
In GitLab each change to the codebase starts with an issue in the issue tracking system. In GitLab, each change to the codebase starts with an issue in the issue tracking system.
If there is no issue yet it should be created first provided there is significant work involved (more than 1 hour). If there is no issue yet, create the issue, as long as the change will take a significant amount of work, i.e., more than 1 hour.
For many organizations this will be natural since the issue will have to be estimated for the sprint. In many organizations, raising an issue is part of the development process because they are used in sprint planning.
Issue titles should describe the desired state of the system, e.g. "As an administrator I want to remove users without receiving an error" instead of "Admin can't remove users.". The issue title should describe the desired state of the system.
For example, the issue title "As an administrator, I want to remove users without receiving an error" is better than "Admin can't remove users."
When you are ready to code you start a branch for the issue from the master branch.
The name of this branch should start with the issue number, for example '15-require-a-password-to-change-it'. When you are ready to code, create a branch for the issue from the `master` branch.
This branch is the place for any work related to this change.
When you are done or want to discuss the code you open a merge request.
This is an online place to discuss the change and review the code. NOTE: **Note:**
Opening a merge request is a manual action since you do not always want to merge a new branch you push, it could be a long-running environment or release branch. The name of a branch might be dictated by organizational standards.
If you open the merge request but do not assign it to anyone it is a 'Work In Progress' merge request. For example, in GitLab, any branches in GitLab EE that are equivalent to branches in GitLab CE [must end in `-ee`](https://docs.gitlab.com/ee/development/automatic_ce_ee_merge.html#cherry-picking-from-ce-to-ee).
These are used to discuss the proposed implementation but are not ready for inclusion in the master branch yet.
_Pro tip:_ Start the title of the merge request with `[WIP]` or `WIP:` to prevent it from being merged before it's ready. When you are done or want to discuss the code, open a merge request.
A merge request is an online place to discuss the change and review the code.
When the author thinks the code is ready the merge request is assigned to reviewer.
The reviewer presses the merge button when they think the code is ready for inclusion in the master branch. If you open the merge request but do not assign it to anyone, it is a "Work In Progress" merge request.
In this case the code is merged and a merge commit is generated that makes this event easily visible later on. These are used to discuss the proposed implementation but are not ready for inclusion in the `master` branch yet.
Merge requests always create a merge commit even when the commit could be added without one. Start the title of the merge request with "[WIP]" or "WIP:" to prevent it from being merged before it's ready.
This merge strategy is called 'no fast-forward' in git.
After the merge the feature branch is deleted since it is no longer needed, in GitLab this deletion is an option when merging. When you think the code is ready, assign the merge request to a reviewer.
The reviewer can merge the changes when they think the code is ready for inclusion in the `master` branch.
When they press the merge button, GitLab merges the code and creates a merge commit that makes this event easily visible later on.
Merge requests always create a merge commit, even when the branch could be merged without one.
This merge strategy is called "no fast-forward" in Git.
After the merge, delete the feature branch since it is no longer needed.
In GitLab, this deletion is an option when merging.
Suppose that a branch is merged but a problem occurs and the issue is reopened. Suppose that a branch is merged but a problem occurs and the issue is reopened.
In this case it is no problem to reuse the same branch name since it was deleted when the branch was merged. In this case, it is no problem to reuse the same branch name since the first branch was deleted when it was merged.
At any time there is at most one branch for every issue. At any time, there is at most one branch for every issue.
It is possible that one feature branch solves more than one issue. It is possible that one feature branch solves more than one issue.
## Linking and closing issues from merge requests ## Linking and closing issues from merge requests
![Merge request showing the linked issues that will be closed](close_issue_mr.png) ![Merge request showing the linked issues that will be closed](close_issue_mr.png)
Linking to issues can happen by mentioning them in commit messages (fixes #14, closes #67, etc.) or in the merge request description. Link to issues by mentioning them in commit messages or the description of a merge request, for example, "Fixes #16" or "Duck typing is preferred. See #12."
GitLab then creates links to the mentioned issues and creates comments in the corresponding issues linking back to the merge request. GitLab then creates links to the mentioned issues and creates comments in the issues linking back to the merge request.
These issues are closed once code is merged into the default branch. To automatically close linked issues, mention them with the words "fixes" or "closes," for example, "fixes #14" or "closes #67." GitLab closes these issues when the code is merged into the default branch.
If you only want to make the reference without closing the issue you can also just mention it: "Duck typing is preferred. #12". If you have an issue that spans across multiple repositories, create an issue for each repository and link all issues to a parent issue.
If you have an issue that spans across multiple repositories, the best thing is to create an issue for each repository and link all issues to a parent issue.
## Squashing commits with rebase ## Squashing commits with rebase
![Vim screen showing the rebase view](rebase.png) ![Vim screen showing the rebase view](rebase.png)
With git you can use an interactive rebase (`rebase -i`) to squash multiple commits into one and reorder them. With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
In GitLab EE and .com you can also [rebase before merge](http://docs.gitlab.com/ee/workflow/rebase_before_merge.html) from the web interface. This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
This functionality is useful if you made a couple of commits for small changes during development and want to replace them with a single commit or if you want to make the order more logical.
However you should never rebase commits you have pushed to a remote server. However, you should never rebase commits you have pushed to a remote server.
Somebody can have referred to the commits or cherry-picked them. Rebasing creates new commits for all your changes, which can cause confusion because the same change would have multiple identifiers.
When you rebase you change the identifier (SHA-1) of the commit and this is confusing. It also causes merge errors for anyone working on the same branch because their history would not match with yours.
If you do that the same change will be known under multiple identifiers and this can cause much confusion. Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed since the last review.
If people already reviewed your code it will be hard for them to review only the improvements you made since then if you have rebased everything into one commit.
Another reasons not to rebase is that you lose authorship information, maybe someone created a merge request, another person pushed a commit on there to improve it and a third one merged it. You should also never rebase commits authored by other people.
In this case rebasing all the commits into one prevent the other authors from being properly attributed and sharing part of the [git blame](https://git-scm.com/docs/git-blame). Not only does this rewrite history, but it also loses authorship information.
Rebasing prevents the other authors from being attributed and sharing part of the [`git blame`](https://git-scm.com/docs/git-blame).
People are encouraged to commit often and to frequently push to the remote repository so other people are aware what everyone is working on.
This will lead to many commits per change which makes the history harder to understand. If a merge involves many commits, it may seem more difficult to undo.
But the advantages of having stable identifiers outweigh this drawback. You might think to solve this by squashing all the changes into one commit before merging, but as discussed earlier, it is a bad idea to rebase commits that you have already pushed.
And to understand a change in context one can always look at the merge commit that groups all the commits together when the code is merged into the master branch. Fortunately, there is an easy way to undo a merge with all its commits.
The way to do this is by reverting the merge commit.
After you merge multiple commits from a feature branch into the master branch this is harder to undo. Preserving this ability to revert a merge is a good reason to always use the "no fast-forward" (`--no-ff`) strategy when you merge manually.
If you had squashed all the commits into one you could have just reverted this commit but as we indicated you should not rebase commits after they are pushed.
Fortunately [reverting a merge made some time ago](https://git-scm.com/blog/2010/03/02/undoing-merges.html) can be done with git. NOTE: **Note:**
This however, requires having specific merge commits for the commits your want to revert. If you revert a merge commit and then change your mind, revert the revert commit to redo the merge.
If you revert a merge and you change your mind, revert the revert instead of merging again since git will not allow you to merge the code again otherwise. Git does not allow you to merge the code again otherwise.
Being able to revert a merge is a good reason always to create a merge commit when you merge manually with the `--no-ff` option. ## Reducing merge commits in feature branches
Git management software will always create a merge commit when you accept a merge request.
## Do not order commits with rebase
![List of sequential merge commits](merge_commits.png) ![List of sequential merge commits](merge_commits.png)
With git you can also rebase your feature branch commits to order them after the commits on the master branch. Having lots of merge commits can make your repository history messy.
This prevents creating a merge commit when merging master into your feature branch and creates a nice linear history. Therefore, you should try to avoid merge commits in feature branches.
However, just like with squashing you should never rebase commits you have pushed to a remote server. Often, people avoid merge commits by just using rebase to reorder their commits after the commits on the `master` branch.
This makes it impossible to rebase work in progress that you already shared with your team which is something we recommend. Using rebase prevents a merge commit when merging `master` into your feature branch, and it creates a neat linear history.
When using rebase to keep your feature branch updated you [need to resolve similar conflicts again and again](https://blogs.atlassian.com/2013/10/git-team-workflows-merge-or-rebase/). However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should never rebase commits you have pushed to a remote server.
You can reuse recorded resolutions (rerere) sometimes, but without rebasing you only have to solve the conflicts one time and you’re set. This restriction makes it impossible to rebase work in progress that you already shared with your team, which is something we recommend.
There has to be a better way to avoid many merge commits.
The way to prevent creating many merge commits is to not frequently merge master into the feature branch.
We'll discuss the three reasons to merge in master: leveraging code, merge conflicts, and long running branches.
If you need to leverage some code that was introduced in master after you created the feature branch you can sometimes solve this by just cherry-picking a commit.
If your feature branch has a merge conflict, creating a merge commit is a normal way of solving this.
You can prevent some merge conflicts by using [gitattributes](http://git-scm.com/docs/gitattributes) for files that can be in a random order.
For example in GitLab our changelog file is specified in .gitattributes as `CHANGELOG.md merge=union` so that there are fewer merge conflicts in it.
The last reason for creating merge commits is having long lived branches that you want to keep up to date with the latest state of the project.
Martin Fowler, in [his article about feature branches](http://martinfowler.com/bliki/FeatureBranch.html) talks about this Continuous Integration (CI).
At GitLab we are guilty of confusing CI with branch testing. Quoting Martin Fowler: "I've heard people say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
That's continuous building, and a Good Thing, but there's no integration, so it's not CI.".
The solution to prevent many merge commits is to keep your feature branches short-lived, the vast majority should take less than one day of work.
If your feature branches commonly take more than a day of work, look into ways to create smaller units of work and/or use [feature toggles](http://martinfowler.com/bliki/FeatureToggle.html).
As for the long running branches that take more than one day there are two strategies.
In a CI strategy you can merge in master at the start of the day to prevent painful merges at a later time.
In a synchronization point strategy you only merge in from well defined points in time, for example a tagged release.
This strategy is [advocated by Linus Torvalds](https://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html) because the state of the code at these points is better known.
In conclusion, we can say that you should try to prevent merge commits, but not eliminate them.
Your codebase should be clean but your history should represent what actually happened.
Developing software happen in small messy steps and it is OK to have your history reflect this.
You can use tools to view the network graphs of commits and understand the messy history that created your code.
If you rebase code the history is incorrect, and there is no way for tools to remedy this because they can't deal with changing commit identifiers.
## Award emojis on issues and merge requests Rebasing also creates more work, since every time you rebase, you have to resolve similar conflicts.
Sometimes you can reuse recorded resolutions (`rerere`), but merging is better since you only have to resolve conflicts once.
Atlassian has a more thorough explanation of the tradeoffs between merging and rebasing [on their blog](https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase).
![Emoji bar in GitLab](award_emoji.png) A good way to prevent creating many merge commits is to not frequently merge `master` into the feature branch.
There are three reasons to merge in `master`: utilizing new code, resolving merge conflicts, and updating long-running branches.
It is common to voice approval or disapproval by using +1 or -1. In GitLab you If you need to utilize some code that was introduced in `master` after you created the feature branch, you can often solve this by just cherry-picking a commit.
can use emojis to give a virtual high five on issues and merge requests.
## Pushing and removing branches If your feature branch has a merge conflict, creating a merge commit is a standard way of solving this.
![Remove checkbox for branch in merge requests](remove_checkbox.png) NOTE: **Note:**
Sometimes you can use .gitattributes to reduce merge conflicts.
For example, you can set your changelog file to use the [union merge driver](https://git-scm.com/docs/gitattributes#gitattributes-union) so that multiple new entries don't conflict with each other.
We recommend that people push their feature branches frequently, even when they are not ready for review yet. The last reason for creating merge commits is to keep long-running feature branches up-to-date with the latest state of the project.
By doing this you prevent team members from accidentally starting to work on the same issue. The solution here is to keep your feature branches short-lived.
Of course this situation should already be prevented by assigning someone to the issue in the issue tracking software. Most feature branches should take less than one day of work.
However sometimes one of the two parties forgets to assign someone in the issue tracking software. If your feature branches often take more than a day of work, try to split your features into smaller units of work.
After a branch is merged it should be removed from the source control software.
In GitLab and similar systems this is an option when merging. If you need to keep a feature branch open for more than a day, there are a few strategies to keep it up-to-date.
This ensures that the branch overview in the repository management software shows only work in progress. One option is to use continuous integration (CI) to merge in `master` at the start of the day.
This also ensures that when someone reopens the issue a new branch with the same name can be used without problem. Another option is to only merge in from well-defined points in time, for example, a tagged release.
When you reopen an issue you need to create a new merge request. You could also use [feature toggles](https://martinfowler.com/bliki/FeatureToggle.html) to hide incomplete features so you can still merge back into `master` every day.
> **Note:** Don't confuse automatic branch testing with continuous integration.
> Martin Fowler makes this distinction in [his article about feature branches](https://martinfowler.com/bliki/FeatureBranch.html):
>
> "I've heard people say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
> That's continuous building, and a Good Thing, but there's no *integration*, so it's not CI."
In conclusion, you should try to prevent merge commits, but not eliminate them.
Your codebase should be clean, but your history should represent what actually happened.
Developing software happens in small, messy steps, and it is OK to have your history reflect this.
You can use tools to view the network graphs of commits and understand the messy history that created your code.
If you rebase code, the history is incorrect, and there is no way for tools to remedy this because they can't deal with changing commit identifiers.
## Commit often and push frequently
Another way to make your development work easier is to commit often.
Every time you have a working set of tests and code, you should make a commit.
Splitting up work into individual commits provides context for developers looking at your code later.
Smaller commits make it clear how a feature was developed, and they make it easy to roll back to a specific good point in time or to revert one code change without reverting several unrelated changes.
Committing often also makes it easy to share your work, which is important so that everyone is aware of what you are working on.
You should push your feature branch frequently, even when it is not yet ready for review.
By sharing your work in a feature branch or [a merge request](#mergepull-requests-with-gitlab-flow), you prevent your team members from duplicating work.
Sharing your work before it's complete also allows for discussion and feedback about the changes, which can help improve the code before it gets to review.
## Committing often and with the right message ## How to write a good commit message
![Good and bad commit message](good_commit.png) ![Good and bad commit message](good_commit.png)
We recommend to commit early and often. A commit message should reflect your intention, not just the contents of the commit.
Each time you have a functioning set of tests and code a commit can be made. It is easy to see the changes in a commit, so the commit message should explain why you made those changes.
The advantage is that when an extension or refactor goes wrong it is easy to revert to a working version. An example of a good commit message is: "Combine templates to reduce duplicate code in the user views."
This is quite a change for programmers that used SVN before, they used to commit when their work was ready to share. The words "change," "improve," "fix," and "refactor" don't add much information to a commit message.
The trick is to use the merge/pull request with multiple commits when your work is ready to share. For example, "Improve XML generation" could be better written as "Properly escape special characters in XML generation."
The commit message should reflect your intention, not the contents of the commit. For more information about formatting commit messages, please see this excellent [blog post by Tim Pope](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
The contents of the commit can be easily seen anyway, the question is why you did it.
An example of a good commit message is: "Combine templates to dry up the user views.".
Some words that are bad commit messages because they don't contain much information are: change, improve and refactor.
The word fix or fixes is also a red flag, unless it comes after the commit sentence and references an issue number.
To see more information about the formatting of commit messages please see this great [blog post by Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
## Testing before merging ## Testing before merging
![Merge requests showing the test states, red, yellow and green](ci_mr.png) ![Merge requests showing the test states: red, yellow, and green](ci_mr.png)
In old workflows the Continuous Integration (CI) server commonly ran tests on the master branch only.
Developers had to ensure their code did not break the master branch.
When using GitLab flow developers create their branches from this master branch so it is essential it is green.
Therefore each merge request must be tested before it is accepted.
CI software like Travis and GitLab CI show the build results right in the merge request itself to make this easy.
One drawback is that they are testing the feature branch itself and not the merged result.
What one can do to improve this is to test the merged result itself.
The problem is that the merge result changes every time something is merged into master.
Retesting on every commit to master is computationally expensive and means you are more frequently waiting for test results.
If there are no merge conflicts and the feature branches are short lived the risk is acceptable.
If there are merge conflicts you merge the master branch into the feature branch and the CI server will rerun the tests.
If you have long lived feature branches that last for more than a few days you should make your issues smaller.
## Working with feature branches In old workflows, the continuous integration (CI) server commonly ran tests on the `master` branch only.
Developers had to ensure their code did not break the `master` branch.
When using GitLab flow, developers create their branches from this `master` branch, so it is essential that it never breaks.
Therefore, each merge request must be tested before it is accepted.
CI software like Travis CI and GitLab CI show the build results right in the merge request itself to make this easy.
![Shell output showing git pull output](git_pull.png) There is one drawback to testing merge requests: the CI server only tests the feature branch itself, not the merged result.
Ideally, the server could also test the `master` branch after each change.
However, retesting on every commit to `master` is computationally expensive and means you are more frequently waiting for test results.
Since feature branches should be short-lived, testing just the branch is an acceptable risk.
If new commits in `master` cause merge conflicts with the feature branch, merge `master` back into the branch to make the CI server re-run the tests.
As said before, if you often have feature branches that last for more than a few days, you should make your issues smaller.
When initiating a feature branch, always start with an up to date master to branch off from. ## Working with feature branches
If you know beforehand that your work absolutely depends on another branch you can also branch from there.
If you need to merge in another branch after starting explain the reason in the merge commit.
If you have not pushed your commits to a shared location yet you can also rebase on master or another feature branch.
Do not merge in upstream if your code will work and merge cleanly without doing so, Linus even says that [you should never merge in upstream at random points, only at major releases](https://lwn.net/Articles/328438/).
Merging only when needed prevents creating merge commits in your feature branch that later end up littering the master history.
### References ![Shell output showing git pull output](git_pull.png)
- [Git Flow by Vincent Driessen](http://nvie.com/posts/a-successful-git-branching-model/) When creating a feature branch, always branch from an up-to-date `master`.
If you know before you start that your work depends on another branch, you can also branch from there.
If you need to merge in another branch after starting, explain the reason in the merge commit.
If you have not pushed your commits to a shared location yet, you can also incorporate changes by rebasing on `master` or another feature branch.
Do not merge from upstream again if your code can work and merge cleanly without doing so.
Merging only when needed prevents creating merge commits in your feature branch that later end up littering the `master` history.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment