When you are using Git for work and personal repositories although you can logically separate them in separate folders, you can accidentally commit in your personal repository with your work account and visa versa. It is annoying and in some cases might break employer policies as well. Luckily with GitHooks it’s possible to set up a pre-commit hook that allows you to use the correct email address for the correct repository, check the blogpost for how…

Scenario

So, let’s work through this scenario… When you set up your Git repository for the first time you’ll set up a personal username and email globally with the following commands…

git config --global user.name "Tarun Arora"
git config --global user.email "[email protected]"

You can obviously overwrite this per git repository as well by running the following commands within the scope of the specific repository…

cd myWorkRepository
git config user.email "[email protected]"
# print the configuration
git config user.email
tarun_dot_b_dot_arora@avanade.com

Now you would probably clone your work repositories hypothetically in the directory C:\Repos\Work\ and clone your personal repositories hypothetically in the directory C:\Repos\Personal\

Now if you forget to set up an email for your work repository, your globally configured personal email address would be used when committing to your work id. Not ideal!

Interested in learning how you can go from zero to DevOps; Learn real world strategies and application of DevOps. Learn how to use apply modern engineering practices with Azure & VSTS to go from Continuous Integration to Continuous Delivery to Continuous Deployment! Open & Free course on DevOps - Ci to Cd

GitHooks to the rescue

Git hooks allow you to run custom scripts whenever certain important events occur in the Git life-cycle, such as committing, merging, and pushing. Git ships with a number of sample hook scripts in the repo\.git\hooks directory.

More specifically it is the Pre-Commit GitHook that we’ll put to work to trigger a script ahead of committing the changes to validate the email address…

Now if you are on windows, simply renaming the file won’t work. Git will fail to find shell in the designated path as specified in the script. The problem was lurking in the first line of the script, the shebang declaration:

#!/bin/sh

On Unix-like OS’s, the #! tells the program loader that this is a script to be interpreted, and /bin/sh is the path to the interpreter you want to use, sh in this case. Windows is definitely not a Unix-like OS. Git for Windows supports Bash commands and shell scripts via Cygwin. By default, what does it find when it looks for sh.exe at /bin/sh? Yup, nothing; nothing at all. Fix it by providing the path to the sh executable on your system. I’m using the 64-bit version of Git for Windows, so my shebang line looks like this.

#!C:/Program\ Files/Git/usr/bin/sh.exe
#!C:/Program\ Files/Git/usr/bin/sh.exe
PWD=`pwd`
if [[ $PWD == *"Work"* ]] # 1)
then
  EMAIL=$(git config user.email)
  if [[ $EMAIL == *"avanade"* ]] # 2)
  then
    echo "";
  else
    echo "email not configured to Avanade in Work directory";
    echo "run:"
    echo '   git config user.email "[email protected]"'
    echo ''
    exit 1; # 3)
  fi;
fi;

If shell isn’t your think, luckily GitHooks support PowerShell as well, check out my other blogpost on how to get GitHooks working on Windows with PowerShell here

So, let’s see what we did here,

  • Check the directory the repository resides in
  • If the repository is in the work directory
  • Check the email currently configured
  • If it’s not Avanade, set it up to be Avanade

What are the other options?

Since Version 2.9 of Git, there is now built in support for global GitHooks that you can share by committing with in the repository… This means, not can you only benefit from this GitHook, but a generic version of this can be put to work for others that clone this repository…

Now version 2.13 of GIt, supports conditional includes… See Below…

 * The configuration file learned a new "includeIf.<condition>.path"
   that includes the contents of the given path only when the
   condition holds.  This allows you to say "include this work-related
   bit only in the repositories under my ~/work/ directory".

Think of it as a global configuration that gives you an option apply the global configuration depending on specific conditions, i think you have got the idea… Check out this blogpost from Thomas Edward that covers the implementation on how to set this up…

Hope you found this useful…

Tarun


About author
Tarun Arora
Tarun Arora
Tarun Arora is obsessed with high-quality working software, DevOps, Continuous Delivery and Agile. His core strengths are Azure, Azure DevOps, PowerShell, SQL and WPF. He is a Microsoft MVP in Visual Studio Development Tools and the author of 'DevOps & ALM with TFS 2015'.
We Are
  • onlyutkarsh
    Utkarsh Shigihalli
    Microsoft MVP, Technologist & DevOps Coach


  • arora_tarun
    Tarun Arora
    Microsoft MVP, Author & DevOps Coach at Avanade

Do you like our posts? Subscribe to our newsletter!
Our Book