Using and maintaining a clean feature branch workflow

Softray Solutions
6 min readMar 5, 2020

Written by Raisa Seferagic, Software Developer at Softray Solutions

When deciding which workflow a team should follow, the very first thing you need to decide is what’s the most beneficial for your team. If you prefer having long-lived branches where at any point in the future you can look back and find a branch that is responsible for exactly one feature, you should consider using the feature branch workflow. A team can also benefit from knowing some tricks on how to rewrite commit history, knowing what WIP pull requests are, and choosing which merge strategy to use in your project. Those are the main topics covered in this blog.

Feature Branch Workflow

The main idea of this workflow is that each branch contains only the code that implements the corresponding feature. There is one main (master) branch and each feature branch is created from it. This workflow type will not allow the main branch to be ‘broken’ so easily. Also, it makes it possible to leverage the pull requests which are a great opportunity for your team to teach and learn. Advanced developers can sign off on a feature to go public, give you an idea how to improve your code or ease the readability. When changing a lot of code (e.g. big refactoring) it would be a good choice to use feature branches because these changes wouldn’t be affecting other team members and can be committed as often as needed. The main disadvantage of using this type of workflow is the higher risk of having merge conflicts, but it can be avoided by keeping the feature small and syncing your branch with the remote often.

Even if you’re using feature branch workflow in hopes of having a well-organized structure, the commit history can get messy. In order to avoid that, it can be helpful to learn how to properly rewrite git history. This can be done in a few ways, such as rebasing the branch, amending commits or using squash merge strategy. The following section will provide more details about a specific method: amending commits.

Amending commits

First of all, what does amending a commit mean? When you make changes on a feature after you’ve already created a commit, you can use amend to combine the staged changes with changes made in the previous commit. Also, you can use amend to simply change the commit message. It’s extremely important to keep in mind that rewriting history should not be done with commits that are already shared with other team members, either on master branch or the feature branch that some other team member might also be using. If you’ve merged your feature branch to master, amending the commit can only cause confusions. That being said, you should use rewriting history strategies with feature branches that only you’re working on.

There are a few ways you can amend a commit, depending on whether you’ve already pushed the commit or not. In case you have created a commit, but it’s still not public, you can make the changes to the code (if needed) and use the following command:

git commit -–amend

When you’re ready, you can simply use git push. If your commit is already published, you can still use the previous command to amend, but when publishing the new commit you need to use:

git push --forceorgit push --force-with-lease

But be warned: pushing with -f is a very dangerous thing.
Proceed with caution and always be sure that you’re pushing to the right branch.

What it’ll do is it’ll overwrite a remote with your local branch, and some of your teammates’ commits may be lost. Much better and safer option is to always use force-with-lease, because that way it won’t happen that you overwrite someone’s code.

Also, amending a commit that’s not the latest or amending multiple commits is possible by using :

git rebase --i

meaning interactive. This way you can choose what commit(s) to amend.

WIP Pull Request

While working on a feature, changing one file will cause the need for changes in other files and soon enough you’ll have too many changes. The reviewers can get confused and might overlook something that’s possibly important. To avoid this, you can introduce WIP [Work in Progress] pull requests to your workflow.

As soon as you create a new feature branch, make the first change and create a pull request but with adding [WIP] flag before the name. This way, the reviewer can see that your feature is still Work in Progress, but might take a look to see if you’re on the right track, give you early advice. This flag will also disable the merge button. As soon as you create your last commit, you remove the [WIP] flag so the reviewers can give their final approval or comment further.

Merge strategies

There are a few ways you can merge your PR to master branch. Some of the strategies that Bitbucket supports are: merge commit, squash and fast forward only.

When using the default option — merge commit — it adds commits from your feature branch to the master head, and creates a new merge commit. This is good when you want to see the complete history as it is shown in a picture below, but it can get messy and you could easily lose track of what each commit represents.

When using fast forward only, the merge request will be rejected if the source branch is not up to date. the commit history would look like in the picture.

Generally, fast-forward strategy for merging pull requests is associated with rebasing the feature branch into master. Rebase + ff-only is a good option when your goal is a clean git history. This can be done manually with:

git rebase master
git merge pr — ff-only

but it is also supported by Bitbucket.

The commits from our feature branch are now visible in the history of the master branch, but no additional commits were made. This also gives us a good representation of all the commits, but we might see some commits that don’t play a big role for our team. When we want to have only one commit for one pull request, we can try using the squash merge strategy.

Squash merge will have our history looking clean and easy to understand, but on the negative side, when using squash merge we might not see some key commits in the history. What it does is that it combines all the commits from our source branch into one, non-merge commit on the target branch. After merging using squash strategy, the source branch needs to be closed in order to avoid any confusion.

Now that we’ve covered basic concepts of feature branch workflow, it might be easier to decide if it’s something your team can benefit from. When using this or any other branching strategy, you should learn some ways of keeping the commit history transparent. After reading this blog you should have an insight on how it can be done.

You can’t incorporate all of the listed items in your project but it may be helpful to try it out and see what suits your team and your project the best.

Having a precisely defined workflow and clean commit history can improve the quality of a project structure and make it easy to understand for any new teammates to come.

If you enjoyed reading this, click on the clap button so others can find this post.

--

--