Front-end D&D (Version Control System & Repository Management)
I can’t tell you how much relief I have after switching from SVN to Git, and I also don’t think anyone would argue with me the fact that Git is far developer-friendly than SVN, especially in branching and merging. (except for those SVN die hard fans 😛)
When ever we heard of Git, the first thing on our mind is GitHub. No doubt GitHub has contributed a lot to the Git adoption rate. But its free tier is for open source projects, my daily work would not be suitable to host on it, so I chose Atlassian Bitbucket instead. Bitbucket allows a team of lesser than 5 to host unlimited private repositories on them. Great fit!
I am not a 100% command-line type of developer. Though I do use the terminal for other stuff in my workflow. But for Git, I am using a GUI client: Atlassian SourceTree for basic actions, i.e. clone a repo, checking for history/commits, pulling sub-modules, etc. And all the other actions are mainly performed within the IDE (check out the upcoming story on IDE), i.e. commit, checkout new branches, resolve conflicts, merges, etc.
Sourcetree is great but it also slow! On and off you will need to wait for seconds on a simple action, i.e. listing of history. So prepare to get annoyed once in a while.
I can’t complete this section without describing current branching model that I am sitting on. If you are into branching and merging for some times, you should have heard about git-flow. I was on git-flow for few years, it was all good. Though managing different branches might not be best suit for a small team. So I have kind of simplified the model.
For feature development:
- Only keep one main branch: develop
- Remove master branch (both local and remote), since it is quite a confusing term. No worries about it being ‘master’, since for Git, it is just another branch. meh.
- Commit into develop branch for day to day work.
- When a feature is needed, or multiple features in the pipeline, consider branch out like: feature/new-feature-1, feature/new-feature-2.
- Merge into develop branch when the feature is completed/ready to put on release.
For release:
- Bump the ‘minor’ version of the current develop branch.
- Tag the version onto the new commit.
- Release/Deploy the commit to environment(s).
- Re-tag all the environment tags with [environment]_rollback, i,.e. staging becomes staging_rollback.
- Tag the environment name on the deployed commit, i.e. production, latest, staging, etc.
For bug/hot fix:
- Branch out from the current production/latest tag and work on the fix. Could name them like: hotfix/new-hotfix-1
- Rebase back to the develop branch. Rebase is used here for cleaner history, you can choose to do a merge.
- Release a ‘patch’ for that fix.
- Delete the bug/hot fix branch for cleaner log.
If there are roles and permissions in the team, consider Pull Request (PR). The gist of the PR on top of above model:
- Set develop A to be in-charge of review and merge PR.
- Develop B branch out from feature branch to work on. Commit and push to repo.
- Develop B create a PR to merge into the feature branch.
- Develop A review and merge the PR into feature branch.
- If the PR branch is not needed, consider close it after merge.
I have provided some scripts I am using for above process, these are just helper scripts, serve the purpose, over and out.
For tagging environment on specific commit:
tag.sh
#!/bin/bashif [ -z "$1" ]
then
echo "Environment needed. tag.sh ENV [#commit_hash branch tag]"
exit
fi
if [ -z "$2" ]
then
if [ "$1" == "all" ]
then
git tag -f staging
git tag -f production
else
git tag -f $1
fi
else
if [ "$1" == "all" ]
then
git tag -f staging $2
git tag -f production $2
else
git tag -f $1 $2
fi
fi
git push -f --tags
For tagging environment rollback:
tag_rollback.sh
#!/bin/bash
if [ -z "$1" ]
then
echo "Environment needed. tag_rollback.sh ENV"
exit
fi
if [ "$1" == "all" ]
then
if git tag --list | egrep "^staging$"
then
git tag -f staging_rollback staging
git tag -d staging
git push --delete origin staging
fi if git tag --list | egrep "^production"
then
git tag -f latest_rollback production
git tag -d production
git push --delete origin production
fi
else
if git tag --list | egrep "^$2$"
then
git tag -f $2_rollback $2
git tag -d $2
git push --delete origin $2
fi
fi
git push -f --tags
For starting a bug/hot fix:
hotfix_start.sh
#!/bin/bash
if [ -z "$1" ]
then
echo "hotfix name needed. hotfix_start.sh NAME [#commit_hash #branch #tag]"
exit
fi
if [ -z "$2" ]
then
FIX=$1
BASE=production
else
FIX=$1
BASE=$2
fi
git branch hotfix/$FIX $BASE
git checkout hotfix/$FIX
git submodule update
For finishing a bug/hot fix:
hotfix_finish.sh
#!/bin/bash
# 1. Rebase on develop
if [ -z "$1" ]
then
echo "hotfix name needed. hotfix_finish.sh NAME [service]"
exit
fi
# 1.
# Will open up editor, delete the commit for Build
git rebase -i develop || exit 0
# If rebase not successful run hotfix_finish_rebase.sh after resolve manually
hotfix_finish_rebase.sh $1
Script after resolve (if any):
hotfix_finish_rebase.sh
#!/bin/bash
# Continue after rebase
# 2. Switch to develop
# 3. Pull in hot fix
# 4. Switch back to hotfix branch
# 5. Create a patch
# 6. Delete the hot fix branch
# 7. Push tags
if [ -z "$1" ]
then
echo "hotfix name needed. hotfix_finish_rebase.sh NAME [service]"
exit
fi
# 2.
git checkout develop
# 3.
git merge hotfix/$1 --no-edit
# 4.
git checkout hotfix/$1
# 5.
release_hotfix.sh
# 6.
git checkout develop
git branch -D hotfix/$1
# 7.
git push -f --tags
For releasing a bug/hot fix:
release_hotfix.sh
#!/bin/bash
# Stash the current unchanged file, just in case
touch stash.file
git stash save -u -q
echo ">>> Bump Version"VERSION=$(npm version patch-m "#comment Bump version") || exit 0
echo ""
# git branch release/$VERSION
git tag -f $VERSION
# Push all tags
git push -f --tags
# Pop out the last
git stash pop -q
rm -rf stash.file
For general feature release:
release.sh
#!/bin/bash
# Stash the current unchanged file
touch stash.file
git stash save -u -q
echo ">>> Bump Version"if [ -z "$1" ]
then
VERSION=$(npm version minor -m "#comment Bump version") || exit 0
else
VERSION=$(npm version $1 -m "#comment Bump version") || exit 0
fi
echo ""
# Set the rollback tags
tag_rollback.sh all
# git branch release/$VERSION
git tag -f $VERSION
# Push all tags
git push -f --tags
# Pop out the last
git stash pop -q
rm -rf stash.file
For closing a PR:
close_pr.sh
#!/bin/bash
echo "Fetch and prune..."git fetch --tags --prune origin
pullDev() {
echo ""
echo "Checking out develop..."
git checkout develop
echo ""
echo "Pulling develop..."
git pull
}
if [ $# -eq 1 ]
then
pullDev
fi
if [ $# -eq 2 ]
then
if [ "$2" == "d" -o "$2" == "D" ]
then
pullDev
echo ""
echo "Deleting $1..."
git branch -d $1
else
echo ""
echo "Checking out $2..."
git checkout $2
echo ""
echo "Pulling $2..."
git pull
fi
fi
if [ $# -eq 3 ]
then
echo ""
echo "Checking out $2..."
git checkout $2
echo ""
echo "Pulling $2..."
git pull
if [ "$3" == "d" -o "$3" == "D" ]
then
echo ""
echo "Deleting $1..."
git branch -d $1
fi
fi