Version Control: Git, Git Flow
An individual review article for PPL UI 2020 Course
Version Control?
Known also as the Version Control System (VCS), Version Control allows organised team management within a development team. Realistically, different team members or developers will be working on different things at the same time and the changes made by each developer may not necessarily be compatible with other versions of the project developed by other developers. VCS will help solve problems like this by tracking individual changes and have a merging system to prevent any conflicts within the project.
Git?
Git is one of a VCS and is probably the most popular. In this article, we will talk more about how to use Git as your VCS choice. Here are the most often used git commands and how my team have implemented it:
- git init: initialise an existing directory into a git repository
I use this when I first created the directory where I will store my work for the project:
- git clone: create a local copy of an existing remote repository (files, branches, commits)
I use this whenever I want to download the whole remote repository of a project. As seen below, when you clone, an additional folder is created and the repository will be downloaded there:
- git pull: pull or download all changes and commits to your local repository
I use this whenever I want to update my local repository to the current remote repository. Additionally, when I move to another branch using git checkout (explained later), I use git pull to make sure I have the newest version or updates of that branch.
In the example below, I currently have the newest updates of the Staging branch, so it gives me an “Already up to date.” message:
- git checkout: switch between branches
I use this to change or make new branches through my terminal. An example can be seen previously in the example for git pull where I did a checkout to the staging branch. But here is when I want to go to a new branch:
- git status: shows the files where you made changes to in your local repository and gives indication if they have been committed or not.
I use this to check which files I have made changes to and whether or not I have committed them in my local repository:
- git commit: save changes and commit them in your local repository before you push your work to the remote repository.
Everyone will have to use this to push or upload their work to the remote repository. It is best practice to commit with a message to show what kind of update or change you have done with this commit to better document the progress done. However, before doing git commit, you first have to git add: - git add: add the changes to your local staging area before committing them
Everyone will have to use this before committing or pushing their work. I use a dot “.” (git add .) which means I will add all the changes I’ve done:
- git push: push or upload all the (committed) changes you made in your local repository to the remote repository
After adding and committing the changes done, you push to the remote repository by also specifying which remote repository and which branch you want to push to. Since I am currently not pushing anything to my remote repository, here is just an example of the syntax:
- git merge: merge or combine the changes you did with another branch. Conflicts may arise since some parts of the same file may be too different with each other. You can manually fix these conflicts or choose via git which change you want to implement. You can also merge via the git UI, which is how my team merges branches:
- git stash, git pop: to temporarily stash or keep your changes without committing it. Then use git pop to have the stashed changes loaded back.
- git remote: connect with remote repositories
I use this to initialise a connection with the project repository and to see what repositories I already do have:
- git branch: do actions related to branches such as delete, add, and see what branches are there.
I’ve only ever deleted a branch using this command due to a typo in the name, like so:
- git revert: undo commits you’ve made and makes a new commit to overwrite the commits you want to undo. You’ll need to specify the parent number and commit id to overwrite
I have never implemented this in my team yet. - git reset: undo the commits up to the last commit of a branch. You’ll need to specify which branch you want to reset to.
An example of when I’ve used this is when I made a typo in a commit message, so I reset my branch to the last pushed commit and redo the commit message, removing the typo altogether before pushing. - git rebase: combine commit branches to a new base commit
I have also never implemented this in my team yet. However, a situation where you can use rebase is when you are working in a smaller project where commit history does not need to be preserved since rebase regenerates commits on top of the target branch. In this sense, rebase is said to be simpler while merge has better traceability (from commit history).
An example case of where I would prefer using rebase is when I work on my own project, for example a portfolio website, and I rebase with the master any additional features I have finished implementing. This way, my project history is cleaner than using git merge. It’s safe to use since I am working the project on my own and will not raise confusion with other team members regarding the commit history.
Git Flow
Now that we know the basic commands, let’s dive into the flow of how things work in Git. Git Flow is a pattern that helps the team easily track changes, making the master branch deployment process cleaner.
Branches
As seen in the image above, there are a few main branches with different ‘roles’.
- Master Branch
This is where the source code that is ready to deployed located. The version here should be ready to be used by the user. The Scrum Master will be the one that approves merges to this branch. - Staging Branch
The source code here will be the one from every member of the team. Here is where our team merges into from our individual branches once we finish each PBI. This branch is also the base for our Sprint Reviews. Here is an example of our merge with this branch after finishing our individual tasks and PBI:
- User Story / Individual Branch
Here are where each member push their work before merging with the others’. Right now, we are naming each of our branches with the following syntax: “dev-<name>”.
- Hotfix Branch
This is a branch for fixing errors or bugs coming from the Master branch. We resolve the issues there until pipelines pass and then the Hotfix branch will merge back with Master.
So far, we have not yet the need to involve this branch. - Coldfix Branch
This has similar purpose like Hotfix, but is used for the Staging branch instead of Master. Cases such as the PO rejecting a user story that has been merged into the staging branch, the staging branch will then be reverted. The naming for this branch should be as so: “coldfix-sprint-<sprint_number>”, such as “coldfix-sprint-2”.
So far, we have not yet the need to involve this branch. - Additionally, we have PBI Branches
This branch is where we usually merge our individual tasks to, then the PBI branches are merged into Staging once the Sprint backlogs are finished. To make this branch, we make new branch from the Staging branch:
Now, we have a better knowledge of Git Flow using the commands and branching methods. Here is how our team implements it. First, we do repository initialisation locally:
- git init
- git clone <https.git>/ git remote add <https.git>
Then we make sure there is the staging branch:
- git branch -v (check which branch you are in, make sure in Master)
- git checkout -b staging
After staging is there, we make the PBI branches where the origin branch is from staging.
- git checkout staging
- git checkout -b <PBI_branch>
Then we initialise our user story / individual branches:
- git checkout staging
- git checkout -b dev-<member_name>
- or use the UI method shown previously in the screenshot
After finishing our work, we commit and push them. Surely, we follow TDD discipline where our commits will start from [RED] to [GREEN] with possibly some [REFACTOR]s and/or [CHORE]s without forgetting to make sure our commit messages are descriptive:
- git add .
- git commit -m “[RED/GREEN/REFACTOR/CHORE] <commit_message>”
- git push origin <user_branch>
Once we make sure tests have passed on our story branches, we merge them into the PBI branches:
Here is an example of my merge request to a PBI branch:
After the PBI is done, we merge into the staging branch in a similar way. However, a couple things to mind before merging is:
- all tests have passed (GREEN pipeline)
- rule where at least 2 team members review the code and give their approvals
- uncheck “Remove source branch”
- check “Squash commits”
So, far, this is all that our team has been implementing in our (almost) 2 Sprints. In short, an example is as follows: