Posted on June 17, 2019 Published by

Help Me, Git. You’re My Only Hope.

As someone with dyslexia, there are a few things I struggle with outside of my core development work. Such as spelling, time tracking, leaving in debugging information, and often working in the wrong branch. These silly mistakes would often make me feel embarrassed. I wanted to stop making these mistakes, but I did not want to start using more tools to try to help with these issues.

I wanted to see if I could use something that I was familiar with and that I already used daily. Like many developers I use git, so I decided to see if I could alter how I used git to help with the problems I was facing.

Branches Branches Branches

As a creature of habit, I use the cli when working with git. Often, I would find myself working in the wrong branch, only realising when it was time to deploy work or merge into another branch. I was constantly running ‘git branch’ to check I was in the right branch during development. This, as you can guess, is annoying and also time consuming to get a branch back into the right state before you can complete a merge.

So I made the following change to my .bash_profile.

parse_git_branch() {
    COLOR_RED="\033[0;31m"
     COLOR_YELLOW="\033[0;33m"
     branch=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/')

     if [[ $branch =~ "master" ]]; then
        echo -e $COLOR_RED
        echo  "You are working in your $branch branch"
     else
        echo -e $COLOR_YELLOW
        echo  "$branch"
     fi
}
export PS1="\[email protected]\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $
Master branch warning

Master branch warning

As you can see here, whenever you are in the master branch, the branch name along with a warning is displayed in red. No more working in the wrong branch, no more running ‘git branch’.

Silly Spelling Mistakes

Spelling is not my strong point, especially when quickly typing a commit message. Often, I would submit commit messages such as ‘committing report function’. I wanted to see if I could use a git hook to help me out here.

Git has a cool little (but powerful) feature known as git hooks. Git hooks are scripts that git will execute before or after certain commands. They are built in, so no need to download and install anything to get them running and can be written in any language you like, as long as they can be run as an executable. The hooks sit inside the ‘./git/hooks’ directory inside a git repository. There are many types of git hooks I will focus on are pre-commit and commit-msg.

They also work with the likes of Sourcetree, apart from the commit-msg hook.

Having a look around I found the following code written by Remiprev which used the Hunspell dictionary with the commit-msg hook. Now if a commit message is spelled incorrectly I get the following warning, and the commit will fail.

Failed commit due to spelling mistake

Failed commit due to spelling mistake

If you do need to add a word that is not in the dictionary you can either add this word into the hunspell dictionary,  or just add the “-n” flag to the end of your commit message. “-n” stands for “no verify” so the git hook will be ignored. Also the pre-commit hook fires before the commit-msg hook, so it appears the commit has been successful although the commit has not completed. 

 

Debug, Syntax And Unit Testing

Knowing I could use a git hook to prevent my spelling issues, I was keen to see what else I could do with my commit messages. This is where I started looking into writing my own bash scripts.

The following script I ended up with would check there was no debug left in the script, such as `var_dump`, `print_r` etc, also will run a php linter against any php files. Finally, it will also run a PHPUnit test during a commit. (I ended up taking out the PHPUnit code as it was slowing my commits down too much –  but I have included it in this blog post as an example).

#!/bin/bash
#Redirect output to stderr.
exec 1>&2

# Color codes
red=`tput setaf 1`
green=`tput setaf 2`
blue=`tput setaf 4`
reset=`tput sgr0`


#check for the following `words` in committed items
keywords=(print_r var_dump console\.log)

#put key words together fro grep
keywords_for_grep=$(printf "|%s" "${keywords[@]}")
keywords_for_grep=${keywords_for_grep:1}
#$testSuiteFolder = 'unitTest';

#debugging error counter
debug_found=0

echo "${green}"
echo "Running Unit Tests"
echo "${reset}"

phpunit=`which phpunit`
output=`phpunit ~/foo/bar`
returnCode=$?

"$output" 2>/dev/null


if [ $returnCode -ne 0 ]
then
  # find the line with the summary.
  while read -r line; do
    if [[ $line =~ Failures: ]]
    then
       summary=$line
       break
    fi
   done <<< "$output"
   if [ $debug_found -eq 0 ]
   then
     echo "${red}"
     echo "# Syntax Error(s):"
     echo "-----------------------${reset}"
   fi
   debug_found=1
   echo "$output"
fi

# Ignore the following files.
exclude_dir_and_ext='\/features\/|\/contrib\/|\/devel\/|\/libraries\/|\/vendor\/|\.info$|\.png$|\.gif$|\.jpg$|\.ico$|\.patch$|\.htaccess$|\.sh$|\.ttf$|\.woff$|\.eot$|\.svg$'


# Check for debugging functions
# List all files added to commit excluding the exceptions
files_changed=`git diff-index --diff-filter=ACMRT --cached --name-only HEAD -- | egrep -v $exclude_dir_and_ext`

if [ -n "$files_changed" ]
then
    for FILE in $files_changed ; do
      if [ ${FILE: -4} == ".php" ]
        then
        #run the linter

          syntax_result=$(php -l $FILE 2>/dev/null )


          if [ "$syntax_result" != "No syntax errors detected in $FILE" ]
          then

            if [ $debug_found -eq 0 ]
           then
             echo "${red}"
             echo "# Syntax Error(s):"
             echo "-----------------------${reset}"
           fi
          debug_found=1
          echo "$syntax_result"
        fi
     fi

      # find the pattern
     for keyword in "${keywords[@]}" ; do
       pattern="^\+(.*)?$keyword(.*)?"
       result_for_file=`git diff --cached $FILE | egrep -x "$pattern"`

        if [ ! -z "$result_for_file" ]
       then

         if [ $debug_found -eq 0 ]
         then
           echo "${red}"
           echo "# Debugging function(s):"
           echo "------------------------${reset}"
         fi 

          debug_found=1
         echo "Debugging function" $keyword
         git grep -n $keyword $FILE | awk '{split($0,a,":"); printf "\t found in " a[1] " on line " a[2] "\n";}'
       fi
     done
done

fi

errors_found=$((debug_found))
#stop the commit
if [ $errors_found -eq 0 ]
then
  echo "${green}"
  echo "Your Code is clean from debug and has been committed"
  echo "${reset}"
else


echo "${red}"
echo "degugging found - please fix before commiting"
echo "${reset}"

exit 1
fi

Now if there is a syntax error, a failed unit test or debug left in the code, then the commit will also fail. If you do need to force the commit, again use the ‘-n’ command to force the commit. Sometimes you just need to add in some debug.

Failed commit due to syntax error

Failed commit due to syntax error

Failed commit due to unit test failing

Failed commit due to unit test failing

Wibbly Wobbly Timey Wimey Stuff

Lastly – time tracking. I always find time tracking difficult and a bit of pain. Again I found that git can help with this. The following command  Will present a list of all git commits you have made that day.

`git log --since='midnight' --pretty=format:'%s -  %ad`

I ended up putting this into my bash profile as so:

alias glog="git log --since='midnight' --pretty=format:'%s -  %ad'"
Example of glog

Example of glog

Now, I can simply type glog, to see all my daily commits.

 

Using git to help with your time tracking can also be improved further. I added the following to the commit-msg hook written by Remiprev to make sure that a commit message starts with a ticket number.

message = ARGV[0]
text = File.read(message)

unless text.match(/ticket: [0-9]+/i)
puts "---------------------------------------------------------------------"
puts "Commit message must have valid ticket id."
puts "---------------------------------------------------------------------"
exit 1
end

Now without a valid ticket id, my commits will not commit.

Now, with a ticket id at the start of each commit it is even easier to track my time.

Example of glog with ticket id

Example of glog with ticket id

 

Overall Code Improvements

With the above git hooks and methods in place, I generally feel more confident with my code. I no longer leave in accidental debug and my time tracking has improved. But overall, I am no longer embarrassed about my bad spelling when committing in a code update. It will be good to hear back from you guys if you have used any of the above or if you have any other ways you use git to help out during your application development. Let me know at @jasonbruce88 .

Jason Bruce-Halliwell

Author: Jason Bruce-Halliwell

Jason is a Senior Systems Engineer at Pentest People.
%d bloggers like this: