CastorisCausa

Personal blog and hacks by Raymundo Cassani

Git hook at changing branches

Often when working on experimental Git branches, it is necessary to modify files outside of the Git repository when we change branches to properly test some of the new features. An example of this type of files would be configuration files.

Through the use of Git hooks it is possible to execute a program when a Git action happens, for example when checkout occurs. However, the post-checkout hook is given the SHA-1 ref of the old (origin) and new (destination) branches, rather than their name. Thus if two branches share the same HEAD, it's not possible to distinguish the correct branch only from the ref. A walk-around is to use git reflog to get the names of the old and new branches.

This Bash script (available here) is a post-checkout hook example to do "something" if the new branch name is in a give list, function exists_in_list(). Moreover, it checks if the old or new branch names have ftr- as prefix, and takes does something for the different combinations, function starts_with().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
bash
#!/bin/bash

set -e  # Stop execution of script if a command or pipeline has an error
printf '\nExample post-checkout hook\n'

# These are the parameters given to the hook
# https://git-scm.com/docs/githooks.html#_post_checkout
oldHEAD=$1       # ref of the previous (old) HEAD
newHEAD=$2       # ref of the new HEAD 
checkoutType=$3  # checkout type flag: 1 = changing branches, 
                 #                     0 = retrieving a file from the index

# Since $1 and $2 are the 40-character SHA-1,
# it is not possible to unambiguously determine old- and new branch names
# [[ $checkoutType == 1 ]] && checkoutType='branch' ||  checkoutType='file' ;
# echo 'Checkout type: '$checkoutType
# echo '     old HEAD: '`git name-rev --name-only $oldHEAD`
# echo '     new HEAD: '`git name-rev --name-only $newHEAD`
# https://stackoverflow.com/q/25590267/4859684

# Get branch names from git-reflog
oldBRANCH=`git reflog | awk 'NR==1{ print $6; exit }'`
newBRANCH=`git reflog | awk 'NR==1{ print $8; exit }'`
echo "Old branch: $oldBRANCH"
echo "New branch: $newBRANCH"
echo ""

exists_in_list() {
# Function for determine if a word is in a space-separated list
# https://www.baeldung.com/linux/check-variable-exists-in-list
    LIST=$1
    WORD=$2
    if [[ "$LIST" =~ (" "|^)$WORD(" "|$) ]]; then
        echo 1
    else
        echo 0
    fi
}

starts_with(){
# Function to check if a word start with a given prefix
    WORD=$1
    PREF=$2
    if [[ $WORD =~ ^$PREF* ]]; then
        echo 1
    else
        echo 0
    fi
}

# ACTION IF NEW BRANCH IS IN A GIVEN LIST
# Determine if NEW branch name belongs to a list of names
listBranches="dev tmp test"
isNewList="$(exists_in_list "$listBranches" "$newBRANCH")"
# NEW branch was in list
if [[ $isNewList -eq 1 ]]; then
    printf "New branch: $newBRANCH was in list\n"
    printf ' Do something 0\n'
    exit 0
fi

# ACTION ACCORDING THE NAMES OF OLD TO NEW BRANCH
# Determine if OLD and NEW branch names have a given prefix
isOldFtr="$(starts_with "$oldBRANCH" "ftr-")"
isNewFtr="$(starts_with "$newBRANCH" "ftr-")"

# NoFeature branch to Feature branch
if [[ $isOldFtr -eq 0 ]] && [[ $isNewFtr -eq 1 ]]; then
    printf "Branch switch: $oldBRANCH -> $newBRANCH\n"
    printf ' Do something 1\n'
    exit 0
fi

# Feature branch to NoFeature branch
if [[ $isOldFtr -eq 1 ]] && [[ $isNewFtr -eq 0 ]]; then
    printf "Branch switch: $oldBRANCH -> $newBRANCH\n"
    printf ' Do something 2\n'
    exit 0
fi

# No change in type of branch
if ([[ $isOldFtr -eq 0 ]] && [[ $isNewFtr -eq 0 ]]) || ([[ $isOldFtr -eq 1 ]] && [[ $isNewFtr -eq 1 ]]); then
    printf "Branch switch: $oldBRANCH -> $newBRANCH\n"
    printf ' Do something 3\n'
    exit 0
fi

exit 0

Comments

comments powered by Disqus