Skip to content

Instantly share code, notes, and snippets.

@mattyclarkson
Last active June 15, 2022 10:25
Show Gist options
  • Save mattyclarkson/e3d75fe06548f3ca58053acd5d01b786 to your computer and use it in GitHub Desktop.
Save mattyclarkson/e3d75fe06548f3ca58053acd5d01b786 to your computer and use it in GitHub Desktop.
A shell script to add `safe.directory` to a `.gitconfig`
#!/bin/sh
# Usage: ./safe-directory.sh directory [.gitconfig] [dst]
#
# `git` will throw permission errors when a repository has been cloned with a
# user different to the runtime user. This script allows adding the cloned
# repository to the `safe.directory` configuration variable without the need
# for an installed `git` binary.
#
# This can be useful on CI runners, when the repository has been cloned as the
# `root` user but the build runs inside a container that has a user different
# to `root`. There is no guarantee that the container will have `git`
# installed, hence this script.
#
# Arguments
# directory The directory to add to `safe.directory`
# .gitconfig The `.gitconfig` to parse, defaulting to `~/.gitconfig`
# dst Filepath to write the resulting `git `configuration,
# defaults to the input `.gitconfig`
#
# Examples
# ./safe-directory.sh $CI_PROJECT_DIR
set -eu
# Parse the incoming user arguments
DIRECTORY="${1}"
SRC="${2-"~/.gitconfig"}"
DST="${3-"${SRC}"}"
# shellcheck disable=SC2088,SC2249
case "${DIRECTORY}" in
"~/"*)
SRC="${HOME}/${DIRECTORY#"~/"}"
;;
esac
# shellcheck disable=SC2088,SC2249
case "${SRC}" in
"~/"*)
SRC="${HOME}/${SRC#"~/"}"
;;
esac
# shellcheck disable=SC2088,SC2249
case "${DST}" in
"~/"*)
DST="${HOME}/${DST#"~/"}"
;;
esac
readonly DIRECTORY SRC DST
# Initialize/check the `.gitconfig`
if ! test -f "${SRC}"; then
touch "${SRC}"
fi
if ! test -f "${SRC}"; then
printf >&2 "'%s' is not a normal SRC" "${SRC}"
exit 2
fi
# Write into a temporary file
TMP="$(mktemp /tmp/gitconfig.XXXXXXXXXX)"
readonly TMP
trap 'rm ${TMP}' EXIT
# For each line in the configuration
# Detect any previous `[safe]` section
# Insert the directory
while IFS= read -r LINE; do
# Process the `[safe]` section
if ! "${SAFE-true}"; then
case "${LINE}" in
*"directory"*)
if test "${LINE##*= }" != "${DIRECTORY}"; then
printf "%s\n" "${LINE}" >>"${TMP}"
continue
fi
;;
*)
printf "Adding '%s' to '%s'\n" "${DIRECTORY}" "${SRC}"
;;
esac
SAFE=true
printf "\tdirectory = %s\n" "${DIRECTORY}" >>"${TMP}"
continue
fi
# Detect the `[safe]` section
case "${LINE}" in
"[safe]"*)
printf "%s\n" "${LINE}" >>"${TMP}"
SAFE=false
;;
*)
printf "%s\n" "${LINE}" >>"${TMP}"
;;
esac
done <"${SRC}"
# Add the `[safe]` header if, needed
if test "null" = "${SAFE-null}"; then
printf "[safe]\n" >>"${TMP}"
SAFE=false
fi
# If the directory was never found then add it
if ! "${SAFE:-true}"; then
printf "Adding '%s' to '%s'\n" "${DIRECTORY}" "${SRC}"
printf "\tdirectory = %s\n" "${DIRECTORY}" >>"${TMP}"
fi
# Copy over the temporary file
cp "${TMP}" "${DST}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment