First of all, Merry Christmas everyone (even though it is a bit late)! In this blog post, I want to talk about an introduction to Git branching strategy. The simple question before starting this post: "Have you ever said to yourself that Git in software development is a mistake?" If you're asking the same question to me, my answer is absolutely yes. I used to have a lot of bloody tragedies in Git, especially if the team has a lot of members. The problem may be caused by you or your lovely teammate, which made you to summon everyone in the room to fix the Git issue.
I will provide an example project in https://github.com/freedomofkeima/Git-Branching.
Every great projects in Git start with git init
. You will commit your usual "Initial Commit" and push your project to Git repository.
At this point, you will be presented with master branch (origin/master) and you need to create a development branch, which will be named as dev branch (origin/dev).
git checkout -b dev # create a new dev branch for daily development
git status # ensure that you're in dev branch
git push origin dev # push this newly created branch to origin/dev
It is recommended to update your default branch to dev branch. Most likely, you will not interact with master branch until the next tagging/release. This dev branch will be used as your current HEAD in development environment, while the HEAD of master branch should be consisted of production-ready code.
Let's say we have two team members, which are named by Maki and Saitama. Maki will develop "Feature A" while Saitama will develop "Feature B". Maki decides to create a new Issue in Github, and set the due date to a certain milestone ("Christmas Feature").
In Maki-PC (from local dev branch):
git checkout -b christmas-feature-a # Create "Feature A" branch for Christmas milestone
. . . # Create test.txt
git add --all # Add all modified and untracked files, it is recommended to check "git status"
git commit -a -m "Add test.txt"
git push origin christmas-feature-a
At this point, you will have 3 branches in your repository: master, dev, and christmas-feature-a. After pushing the commit above, Maki decides to go to America and creates a temporary pull request in Github (base = dev, compare = christmas-feature-a). In the same time, Maki puts a tick in "Issue #1" for her first task.
In Saitama-PC (from local dev branch):
git checkout -b unknown-feature-b # Create "Feature B" branch for unknown milestone
. . . # Create test3.txt
git add --all # Add all modified and untracked files, check "git status" previously is recommended
git commit -a -m "Add test3.txt"
git push origin unknown-feature-b
. . . # Create test4.txt
git add --all # Add all modified and untracked files, check "git status" previously is recommended
git commit -a -m "Add test4.txt"
git push origin unknown-feature-b
Saitama decides to create a pull request directly from this commit. Maki reviews this pull request and she gives a LGTM message (Looks Good To Me). Saitama merges unknown-feature-b branch (origin/unknown-feature-b) to dev branch (origin/dev) and close the pull request. After merging, branch unknown-feature-b is deleted from origin.
In Saitama-PC (still in unknown-feature-b local branch):
git checkout dev # go back to dev branch
git pull origin dev # pull latest merge from pull request in origin/dev branch
git branch -d unknown-feature-b # delete branch safely after origin branch is removed (using -d instead of -D)
At this point, it should be impossible to have a conflict between dev branch with master branch, since dev should always reflect the newest state of your development. We will create a release version 1.0.0 with current HEAD in dev branch.
In Saitama-PC (currently in dev local branch):
git checkout -b release-1.0.0 # Create a snapshot branch for release 1.0.0 from current HEAD in dev
git checkout master # Go back to master branch, you may also add the tag before merging to master
git merge --no-ff release-1.0.0 # Merge all changes from release-1.0.0 to master branch (without fast forward)
git checkout dev # Go back to dev branch
git merge --no-ff release-1.0.0 # Merge all changes from release-1.0.0 to dev branch (without fast forward)
At this point, some people prefer to delete the release-1.0.0 branch, while the others keep it for traceability purpose.
Now, you are also ready to create a release version for your clients. You can add a new tag by:
git tag -a 1.0.0 # Add a versioning tag from release-1.0.0
git push origin 1.0.0 # Push tag to repository
You will have a ready-to-serve release, as shown in the following screenshot:
Up until this point, you have learned 4 types of branching: master branch, dev branch, feature branches, and release branches (as a snapshot). We will proceed to the 5th type: hotfix branches. This branch is quite different from your typical feature branches because it needs master branch as its base. This branch serves as severe bug fixes in production environment.
I will skip the step-by-step commands tutorial here. The outline of the steps are provided below:
git checkout -b hotfix-1.0.0 master
git tag -a 1.0.1
and push it to origin)--
At this point, you will have 5 branches in your repository: master, dev, christmas-feature-a, release-1.0.0, and release-1.0.1. In addition, you will have 2 releases under your "releases" tab. If Maki decides to continue her work, her changes are not tainted from other changes https://github.com/freedomofkeima/Git-Branching/pull/2. Finally, other people can review those features independently and merge those branches to dev branch after all tests are successfully passed.
Additional note: Some people prefer to differentiate hotfix and release branches (they put the tag to hotfix branch, instead of creating a release branch). The others prefer not to store both of them in their repository.
Now, you have learned five basics of branching: master branch for HEAD in production, dev branch for HEAD in development, feature branches, release branches, and hotfix branches. If you mistakenly create a commit in wrong branch, you can actually undo it (before pushing it to the repository by):
git reset --soft HEAD^ # revert last commit
git checkout [correct_branch_name] # move to correct branch
git commit # create a commit in the correct branch
Feel free to correct me if I've written something wrong. Happy holiday!
--
Iskandar Setiadi
Software Engineer at HDE, Inc.
Freedomofkeima's Github