I have yet to meet an engineer who does not like to optimise. We like solving puzzles, work with constraints and make science apply to real life. But optimisation is high up there in terms of what we like to do.
If you work in IT these days, not just programming, but as a systems administrator, a project manager, even a designer, you’ve likely got in touch with git
. git
is a distributed source control management tool. In other words, it smartly stores your code (or other artifacts) in a smart way somewhere while at the same time allowing others to work on the same code you are.
I work with git
every day, so when my Harvest colleague Lee Jones, told me about his workflow for git
, I was naturally interested. Less mouse clicks and more automation may only shave a couple of seconds a day, but in the long run they add up. After he shared it, I modified it slightly for my own needs and am sharing it with you below.
Workflow:
branch-me [name of new branch]
- this creates a new branch with my initials prefixed and replaces spaces with hyphensmerge-me
- this pushes the current branch and opens the GitHub PR page. It attempts to set a human-friendly title (e.g. removes my initials, removes hyphens, capitalizes each word)clean-me
- this updates local master branch (git pull
), checks out the master branch, and deletes the feature branchThe script is below and I am sourcing it in my ~/.bash_profile file so that it’s available in every session.
#!/bin/bash
## Originally Lee Jones's workflow, adapted to Miguel David on 12/07/2019
export GIT_BRANCH_PREFIX="md-" # HERE: change prefix as needed
# Creates a branch prefixed with a standard prefix and changes any spaces to dashes
function branch-me() {
if [ "$1" == "" ]
then
echo "ERROR: no branch name provided"
false
else
local branch_name=$(echo -n $GIT_BRANCH_PREFIX[email protected] | sed -e "s/ /-/g")
git checkout -b "${branch_name}"
fi
}
# Pushes the current branch and opens the PR page. Attempts to set the title
# from the branch name.
function merge-me() {
local branch_name="$(_git-current-branch)"
local repo_name="$(_github_repo_name)"
local branch_name_formated_as_title=$(ruby -r uri -e "puts URI.escape(\"$branch_name\").gsub(/^$GIT_BRANCH_PREFIX/, '').gsub('-', ' ').capitalize")
local commit_subjects="$(git log --pretty=%s master...${branch_name})"
local pr_url="https://github.com/${repo_name}/compare/${branch_name}?expand=1"
if [ "${branch_name}" == "master" ]
then
echo "ERROR: you cannot push to master for PR. Switch to a different branch first."
kill -INT $$
fi
# if there are multiple commits, set title by using the branch name
if [[ "$(echo "${commit_subjects}" | wc -l)" -gt "1" ]]
then
pr_url="${pr_url}&title=${branch_name_formated_as_title}"
fi
echo "Opening PR for ${repo_name} from the ${branch_name} branch..."
echo "Pushing ${branch_name} branch to GitHub..."
git push origin "${branch_name}"
echo "Opening PR in browser..."
# Sometimes the compare view does not trigger a new PR - waiting seems to help
sleep 2
open "${pr_url}"
}
# switch to master, pull from origin and merge, delete previous branch
function clean-me() {
local original_branch_name=`_git-current-branch`
local target_branch_name=${1:-master}
if [ "$original_branch_name" = "${target_branch_name}" ]
then
echo "Already on ${target_branch_name} branch, updating..."
git fetch origin
git merge origin/$target_branch_name
else
git fetch origin
git checkout $target_branch_name
git merge origin/$target_branch_name
# If the original branch was rebased before merging, `git branch -d` won't
# work. We can assume it's safe to force deletion if there are effectively
# no differences between the two branches.
if [ "$(git diff $target_branch_name..$original_branch_name --shortstat)" == "" ]; then
git branch -D "${original_branch_name}"
# Otherwise, try to delete the branch normally.
else
if (git branch -d "${original_branch_name}"); then
echo "Successfully deleted branch '$original_branch_name'!"
else
read -p "Do you want to force deletion of branch '$original_branch_name' (y/n)? " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git branch -D "${original_branch_name}"
else
echo "You said '$REPLY'. Exiting!"
return 0
fi
fi
fi
fi
echo "Cleaned up. NEEEXT!"
}
function _git-current-branch() {
echo "$(git branch | grep -E '^\*' | awk '{ print $2 }')"
}
function _github_repo_name() {
local remote_origin_url="$(git config --get remote.origin.url)"
if $(echo "${remote_origin_url}" | grep -q -E "[email protected]:.*\.git"); then
echo "$(echo $remote_origin_url | sed -e 's/[email protected]://' | sed -e 's/.git//')"
else
echo "ERROR: could not determine GitHub repo name from '${remote_origin_url}'."
kill -INT $$
fi
}
I hope this helps!