Github Branch Strategy and Solving Merge Conflicts

Branching

I haven’t written much about tech in a while. As I am still in the process of transitioning from a software engineer to a UX person, I thought it would be good to share a bit about how we use Github to work as a team.

I personally feel that designers that work closely with engineers in a team is a great thing. Designers should learn the basics of how to add assets to projects and how to upload files into Github for collaboration, as well as some basic coding. However, this isn’t always the case, but that is a discussion for another post. I really enjoy having a  mix of both jobs, not only as it’s fun and very rewarding being able to focus on design and still code as well, but it’s also a massive benefit to the team and saves developers time on menial tasks, overall resulting in a better product.

Anyway, I digress.

Our strategy (I’m not sure whether it has a name) helps us as a team collaborate with each other, stakeholders and our users. Our main branches are develop, staging and production. All of these branches have fully functional production code with test coverage and CI. We all get a new build release when any code is pushed to any of these branches.

Develop – Developer code. Developers use this as our base branch – this is where we will branch off from when beginning a new feature. Developers only get notified when code is pushed into this branch. Develop is then pushed into staging.

Staging – Stakeholder’s view this branch. When our feature(s) are in develop and ready, they are pushed into staging and a new build is released for stakeholders to view, where they can check everything is as it should be. Staging data is used. Once approval has been gained, staging can be merged into production.

Production – Our master branch. Full production code, released to users and uses live data. Devices with an existing version of the application will be prompted to update (if native), else changes will be seen on web-apps instantly. Developers, stakeholders and users all get build notifications from production.

When all of this has been setup for a project and we get new features in to produce, we begin by branching off of develop. We name our branches according to whether our tasks are features, chores or bugs. Multiple tasks can be worked on at once across the team, but regular pulls from develop are needed to minimise build conflicts. Rarely, if multiple devs want to work on the same feature, a feature branch will be created and this can be branched off (see diagram). This can be useful if someone is halfway through a feature branch and something else is needed from another team member to complete the feature. Of course, multiple developers can always work off the same feature branch, but I prefer to branch off to minimise problems.

Before any branch is put into develop, a pull request is submitted and (a) member(s) of the team will review and then push to develop. Sometimes there can be merge conflicts, but these can easily be solved using git mergetool.

Rarely, we will have a problem with merging staging into production (native Android has been giving us this problem mainly due to conflicts in the manifest file with version numbers). It can seem daunting when having merge conflicts going into production/master, so here are the steps we use to solve this:

  • Make sure staging and production are FULLY up to date with their remote branches (git pull origin).
  • Pull production INTO staging.
  • Open up git mergetool when prompted and fix the merge conflict in the editor part of the program (if version number, when in doubt use a higher number).
  • Commit changes to staging.
  • Pull request from staging into production: all should be able to merge automatically.

I am aware that many dev teams use different strategies in git but this is the one that works best for us. I recently worked in a team that used git flow and found it not to be as effective, but each to their own. Also, always remember to use git prune 🙂 too many branches gets confusing!

Advertisements

Merge Conflicts From Branch To Branch On Github

Occasionally, there will be a time when you are merging one branch into another on Github (in our case, develop into staging, as our branch hierarchy goes newBranch(es) -> develop -> staging -> master *) and although it may seem scary when that grey box appears, it isn’t difficult to fix. In the example below, we are pushing to develop from staging:

git checkout develop
git pull origin develop
git checkout staging
git status (all should be up to date).
git merge develop
git mergetool (then press 'enter', fix the conflict using the mergetool, save and close, then type 'y' when prompted).
git status (should show you the changed file ready for committing. There may be a '.orig' file duplicated of the file with the conflict - this can be deleted).
git commit -m "Fixed merge conflicts"
git push origin head

This should solve any problems, unless you’ve got a complicated merge on your hands.

* our branch structure is this way not only to avoid merge conflicts and issues, but to fit in with stakeholders’ features. Each branch has to be merged into develop then deleted. Each contributor will be pulling from develop just in case there are any changes. After develop is ready to be shown to stakeholders and test users, with stakeholder warning and approval, develop is pushed into staging. Only after the stakeholder has approved of the changes in staging can staging go into production (master). The main thing we have to be careful of with this is possible problems when the stakeholder doesn’t like a feature in staging, when someone has already pushed another new feature into develop. To avoid this, all contributors have their own branches to work on, and only push to develop when a staging feature has been approved and is being pushed to develop. All the while that they are working on their features, they are pulling from develop to stay up to date.

Github Commands

Github is a social coding tool used as a central place for projects to be stored, so that multiple users can edit the project at the same time without treading on each others toes. There are only a few commands that are needed in order to use Git well (I’d recommend https://try.github.io/levels/1/challenges/1 as a starting point for a fun interactive way to learn the basics), but there are also additional commands to learn. Git can be downloaded onto your desktop, or you can simply use the terminal, which is my personal preference. A repository needs to be set up if you are starting a project, but someone else on our team does this for us.

Here’s a quick introduction on how I use Git for my everyday projects through terminal, including downloading an existing project or committing files into a current project:

ls

Checking my current location. This will bring up a list of all the directories that you can change into to work on your project from. 

cd Documents/Work/Projects/Example_Project

Change directory. In this example, I have gone through my folders to my 'Example_Project'. Because I was aware of the folder progression to get to my needed directory, I have cd'd all in one line. This can be done over several lines of 'ls' and 'cd' to check current locations before going back into them.
Note: Ensure that the correct case is used for your directories. Using 'd' instead of 'D' would make all the difference.
Note: If you have cd'd into the wrong directory, use 'cd ..' to go backwards by one directory.

git clone https://github.com/DigitalInnovation/BigScreen.git

This will begin cloning the chosen repository into your local directory. You can get the clone URL from the repository's Github page.

git status

To check the status of the repository: whether there are any changes from your local to commit, or whether someone else has updated their side of the project and files need to be pulled. It should also tell you which branch you are on.

git branch -a

If you need to know what branch you are currently on or what other branches are available, locally and remotely, enter this command. It will show all the branches in your repository and the one marked with a * is the one that you are working from. 
Note: Branches are used so that people working on the same repository have their own area to work off of for their own feature. There will be a 'master' branch which should never be worked directly from in case something goes wrong - things should only be merged to this branch later on. There should also be a develop branch for new features to be merged to ready for testing and eventually to be merged to master. A new branch should be created with a name for a feature/bug, and then this branch should be used, merged and then deleted once finished with.

git checkout -b newBranch

This command will get you off of your current branch and creating a new branch at the same time.
Note: When creating a new branch, ensure that you are currently on the develop branch so that new branches will come off this file. You should also pull from develop before creating a new branch. The develop branch should be the most up to date branch that people are working from, aside from master. This saves your branches all getting crossed and having merge problems in the future with overlapping code.

git checkout develop

Or you can simply switch to another existing branch.

git branch -d newBranch

To delete the branch locally.

git branch -D newBranch

If you have a problem with the lowercase d, this should get rid of the branch for sure. Make sure you check online that all your changes have been merged before this permanent deletion.

git push origin :newBranch

To delete the branch from the github repo. 
Note: Ensure that there are no merges waiting on the github repo relating to your branch and ensure that you definitely want to do this.

git fetch --all

Fetches all branches.
git remote prune origin

Prunes your branches to get rid of ones that other people may have deleted and that you haven't removed yet. Ensures branch consistency among all those working on the same repo.

git add --all

Adds all changed your files from your local repository ready for committing.

git commit -m "Feature description"

When adding some changes to the git repo, they need to be staged to commit. Once you ensure that you are on the right branch and you have run a git status, they need to be staged. Run this command and enter a description ready for pushing to the remote branch.

git commit -m "comment comment --skip-ci"

As our repo is integrated with Codeship, which does our CI stuff for us, we get notifications. This just stops CI being run every time. When we do a final commit on our branch, then we run the normal git commit without the ci part at the end to ensure that everything is working correctly.

git commit --allow-empty -m "comment"

Runs an empty commit, which is handy when needing to test CI.

git push origin exampleBranch

This will push the changes to Git: from the branch that you have been working on locally to the branch online. After this, one more git status should be entered to check that everything has been committed correctly. 
Note: You can also replace 'exampleBranch' with 'head', which will select all from the local branch.
Note: After going onto Git, you should be able to see the changes that you've committed. To merge these, you need to select your commit and create a new pull request from one branch to the branch you need. You can merge these yourself, but it is better for someone else to code review for you. You can see the code that has been changed and deleted by viewing the commits on github.

git stash

To store your code locally but restore your branch to the last commit. You can get your code back later if needed.

git stash list:

To see what stashes have been stored.

git stash apply

To get the stashed work back.

git pull 

To get files from the repo that others may have committed. When running a git status, you will be told if your local branch isn't up to date with the online one.

git fetch

Longhand for git pull.

git mergetool

Opens up the merge tool to fix any conflicts. Simply save and close then follow the commands in terminal - may need to repeat depending on how many files have conflicts.

i, enter, :wq

When there are sometimes merges that don't require the mergetool - use these commands to enable editing (i), then write your comment in the > sections (using enter and the arrow keys to get there), then exit and save the merge comment (:wq).

git clean  -d  -fx ""

To remove untracked files and directories. Sometimes there will be a message appear when trying to change branches of some untracked files that haven't been committed. This comand will remove them but remember to check whether they are needed, especially as this is a force command (-f)

git reset --soft HEAD^

To move mistakenly committed files from a previous commit back to the staging area. Excellent for when you have added a file into a commit by mistake. Can be used even when the commit has been pushed to a branch, while still saving your changes to them locally.
 
 This is a brief explanation of Git and how I use it day to day. These commands are the common ones used but there are plenty more. You may also end up in Vim...which is hard to get out of!