fix refreshing git-hooks when using git-bash

real symlinks require admin-rights or developer mode, and the other
fallback mechanisms won't work for the version of git that comes with
git-bash. Either spawning the process failes or worse it silently fails
and basically ignores the hook.
MSYS uses regular file copy when using "ln -s" which means to make sure
the current version of a hook is used the hooks need to replaced
everytime or the file contents need to be compared. When using hardlinks
instead it is enough to check whether the source and target share the
same inode.

Change-Id: Ib2e325048779828313afc7fc9d120661d55fc3a5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177498
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
Tested-by: Jenkins
This commit is contained in:
Christian Lohmaier 2024-11-28 14:49:08 +01:00
parent 216a3b2f22
commit caf0071d60

104
g
View file

@ -29,9 +29,23 @@ usage()
echo " -z restore the git hooks and do other sanity checks" echo " -z restore the git hooks and do other sanity checks"
} }
refresh_create_link()
{
local hook_name=$1
local hook=$2
local lnarg=$3
# if it doesn't exist or is neither a symlink nor sharing the same inode (hardlink)
if [ ! -e "${hook?}" ] || [ ! \( -L "${hook?}" -o "${hook_name}" -ef "${hook?}" \) ] ; then
rm -f "${hook?}"
ln -f $lnarg "${hook_name}" "${hook?}"
fi
}
refresh_submodule_hooks() refresh_submodule_hooks()
{ {
local repo=$1 local repo=$1
local lnarg=$2
local hook local hook
local hook_name local hook_name
@ -42,10 +56,7 @@ refresh_submodule_hooks()
continue continue
fi fi
hook="${repo?}/.git/hooks/${hook_name##*/}" hook="${repo?}/.git/hooks/${hook_name##*/}"
if [ ! -e "${hook?}" ] || [ ! -L "${hook?}" ] ; then refresh_create_link "${hook_name}" "${hook?}" "$lnarg"
rm -f "${hook?}"
ln -sf "${hook_name}" "${hook?}"
fi
done done
# override if need be by the submodules' own hooks # override if need be by the submodules' own hooks
for hook_name in "${COREDIR?}/${repo?}/.git-hooks"/* ; do for hook_name in "${COREDIR?}/${repo?}/.git-hooks"/* ; do
@ -53,10 +64,7 @@ refresh_submodule_hooks()
continue continue
fi fi
hook="${repo?}/.git/hooks/${hook_name##*/}" hook="${repo?}/.git/hooks/${hook_name##*/}"
if [ ! -e "${hook?}" ] || [ ! -L "${hook?}" ] ; then refresh_create_link "${hook_name}" "${hook?}" "$lnarg"
rm -f "${hook?}"
ln -sf "${hook_name}" "${hook?}"
fi
done done
elif [ -d .git/modules/"${repo}"/hooks ] ; then elif [ -d .git/modules/"${repo}"/hooks ] ; then
for hook_name in "${COREDIR?}/.git-hooks"/* ; do for hook_name in "${COREDIR?}/.git-hooks"/* ; do
@ -64,10 +72,7 @@ refresh_submodule_hooks()
continue continue
fi fi
hook=".git/modules/${repo?}/hooks/${hook_name##*/}" hook=".git/modules/${repo?}/hooks/${hook_name##*/}"
if [ ! -e "${hook?}" ] || [ ! -L "${hook?}" ] ; then refresh_create_link "${hook_name}" "${hook?}" "$lnarg"
rm -f "${hook?}"
ln -sf "${hook_name}" "${hook?}"
fi
done done
# override if need be by the submodules' own hooks # override if need be by the submodules' own hooks
for hook_name in "${COREDIR?}/${repo?}/.git-hooks"/* ; do for hook_name in "${COREDIR?}/${repo?}/.git-hooks"/* ; do
@ -75,10 +80,7 @@ refresh_submodule_hooks()
continue continue
fi fi
hook=".git/modules/${repo?}/hooks/${hook_name##*/}" hook=".git/modules/${repo?}/hooks/${hook_name##*/}"
if [ ! -e "${hook?}" ] || [ ! -L "${hook?}" ] ; then refresh_create_link "${hook_name}" "${hook?}" "$lnarg"
rm -f "${hook?}"
ln -sf "${hook_name}" "${hook?}"
fi
done done
fi fi
@ -89,63 +91,35 @@ refresh_all_hooks()
local repo local repo
local hook_name local hook_name
local hook local hook
local winlnk
local wingit
local gitbash local gitbash
local lnkfile=".git/hooks/pre-commit" local lnarg
pushd "${COREDIR?}" > /dev/null pushd "${COREDIR?}" > /dev/null
# it is 'GIT for Windows' # it is 'GIT for Windows'
wingit=$(git --version | grep -ic windows)
gitbash=$(echo $OSTYPE | grep -ic msys) gitbash=$(echo $OSTYPE | grep -ic msys)
# In the win-git-bash, do not make links, it makes only copies # git-bash/MSYS doesn't create symlinks by default, and "real" symlinks are restricted to
if [ $gitbash -eq 1 ]; then # Admin-mode or when devmode is activated, junction points as fallback would work for bash/
if [ -d ".git" ]; then # regular use but not when git tries to spawn them, similar for plain windows shortcuts (worse
if [ ! -e "${lnkfile}" ] || [ ! -L "${lnkfile}" ] ; then # because running the hooks will fail silently/they'd be inactive)
# here when wrong link then the file not exist # ln -s without setting MSYS to contain winsymlinks:{lnk,native,nativestrict,sys} to force one
echo "Your hooks not right, solve this in cygwin with" # of the other modes described above will do plain copies.
echo " ./g -z" # So in case of git-bash use hardlinks since those work just fine, everywhere else use symlinks
fi if [ $gitbash -ne 1 ]; then
fi lnarg="--symbolic"
else
if [ $wingit -eq 1 ]; then
# There's no ".git" e.g. in a secondary worktree
if [ -d ".git" ]; then
winlnk=0
if [ -e "${lnkfile}" ] && [ -L "${lnkfile}" ] ; then
# if linux-links or windows-links?
# dos dir output windows link:
# 04.09.2020 10:54 <SYMLINK> pre-commit [..\..\.git-hooks\pre-commit]
# dos dir output linux link:
# file not found
winlnk=$(cmd /C "DIR ${lnkfile//'/'/'\'}" 2>&1)
winlnk=$(echo "$winlnk" | grep -icE "<SYMLINK>.*${lnkfile##*/} \[")
fi
if [ $winlnk -eq 0 ]; then
echo "You using GIT for Windows, but the hook-links not right, change with mklink"
cat .git-hooks/README
fi
fi
else
# There's no ".git" e.g. in a secondary worktree
if [ -d ".git" ]; then
for hook_name in "${COREDIR?}/.git-hooks"/* ; do
hook=".git/hooks/${hook_name##*/}"
if [ ! -e "${hook?}" ] || [ ! -L "${hook?}" ] ; then
rm -f "${hook?}"
ln -sf "${hook_name}" "${hook?}"
fi
done
fi
for repo in ${SUBMODULES_ALL?} ; do
refresh_submodule_hooks "$repo"
done
fi
fi fi
# There's no ".git" e.g. in a secondary worktree
if [ -d ".git" ]; then
for hook_name in "${COREDIR?}/.git-hooks"/* ; do
hook=".git/hooks/${hook_name##*/}"
refresh_create_link "${hook_name}" "${hook?}" "$lnarg"
done
fi
for repo in ${SUBMODULES_ALL?} ; do
refresh_submodule_hooks "$repo" "$lnarg"
done
popd > /dev/null popd > /dev/null