Skip to content

Instantly share code, notes, and snippets.

@pasela
Last active January 17, 2023 13:05
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save pasela/7212517 to your computer and use it in GitHub Desktop.
Save pasela/7212517 to your computer and use it in GitHub Desktop.
git-su - switches user and sshCommand in the current repository
#!/bin/bash
#
# git-su - Git Switch User
# ========================
#
# git-su switches user and sshCommand in the current repository.
#
# USAGE
# -----
#
# git su <-l|--list>
# git su <name>
# git su <name> <git_subcommand> <args...>
#
# e.g. git su -l
# git su foo
# git su foo clone $REPO
#
# git-su sets user.name and user.email by the following command.
# ("Foo" and "foo@example.com" are predefined values)
#
# git config user.name "Foo"
# git config user.email "foo@example.com"
# git config core.sshCommand "ssh -i ~/.ssh/foo_rsa"
#
# You can use the third form for init/clone and set user at one command.
#
#
# DEFINITION FILE
# ---------------
#
# The location of the definition file is '$HOME/.gitsu'. Or You can
# specify the path using $GIT_SU_CONF environment variable.
# Alternatively, you can put definitions into $HOME/.gitconfig directly.
#
# Definition format:
# ------------------------------
# [su "name"]
# name = "Your name"
# email = "Your email address"
# sshCommand = "ssh -i ~/.ssh/id_rsa"
# ------------------------------
# `name` and `email` are mandatory, `sshCommand` is optional.
#
# for example:
# ------------------------------
# [su "alice"]
# name = "Alice"
# email = "alice@example.com"
#
# [su "bob"]
# name = "Bob"
# email = "bob@example.com"
# sshCommand = "ssh -i ~/.ssh/bob_rsa"
# ------------------------------
#
#
# LICENSE
# -------
# MIT License
#
#
# AUTHOR
# -------
#
# Yuki <paselan@gmail.com>
#
GIT_SU_CONF=${GIT_SU_CONF:-$HOME/.gitsu}
PROGNAME=$(basename "$0")
if [[ -n "$1" ]]; then
SU_NAME=$1
else
echo -e "usage: git su <name> [git-subcommand <args>]" 1>&2
exit 1
fi
GIT_VERSION=$(git --version | cut -d" " -f 3)
# from: https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
vercomp () {
if [[ $1 == $2 ]]
then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++))
do
if [[ -z ${ver2[i]} ]]
then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]}))
then
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]}))
then
return 2
fi
done
return 0
}
extract_repo_dir() {
local dir=${@:$#}
[[ -d "$dir" ]] && echo "$dir" && return
dir="${dir##*/}"
[[ -d "$dir" ]] && echo "$dir" && return
dir="${dir%.git}"
[[ -d "$dir" ]] && echo "$dir" && return
pwd
}
print_su_list()
{
git config --name-only --get-regexp '^su\..+\.name$' | sed -e 's/^su\.\(.\+\)\.name$/\1/'
}
get_config()
{
local key=$1
if [[ -e "$GIT_SU_CONF" ]]; then
git config --file "$GIT_SU_CONF" --get "$key" 2>/dev/null && return
fi
git config --get "$key" 2>/dev/null && return
return 1
}
apply_su()
{
local SU_NAME=$1
local USER_NAME USER_EMAIL CORE_SSH_COMMAND
if [[ "$(git rev-parse --is-inside-work-tree)" != "true" ]]; then
return 1
fi
USER_NAME=$(get_config "su.${SU_NAME}.name")
if (( $? != 0 )); then
echo -e "su.${SU_NAME}.name not defined" 1>&2
return 1
fi
USER_EMAIL=$(get_config "su.${SU_NAME}.email")
if (( $? != 0 )); then
echo -e "su.${SU_NAME}.email not defined" 1>&2
return 1
fi
CORE_SSH_COMMAND=$(get_config "su.${SU_NAME}.sshCommand")
if (( $? != 0 )); then
CORE_SSH_COMMAND=
fi
git config user.name "$USER_NAME"
git config user.email "$USER_EMAIL"
if [[ -n "$CORE_SSH_COMMAND" ]]; then
vercomp "$GIT_VERSION" 2.3
if (( $? == 2 )); then
echo "core.sshCommand not supported (Git v${GIT_VERSION} < v2.3)" 1>&2
fi
git config core.sshCommand "$CORE_SSH_COMMAND"
else
git config --unset core.sshCommand
fi
}
su_git()
{
if [[ "$2" == "init" ]] || [[ "$2" == "clone" ]]; then
su_git_outrepo_cmd "$@"
else
su_git_inrepo_cmd "$@"
fi
}
su_git_outrepo_cmd() {
local SU_NAME=$1
shift
vercomp "$GIT_VERSION" 2.3
if (( $? == 2 )); then
echo "core.sshCommand not supported (Git v${GIT_VERSION} < v2.3)" 1>&2
fi
CORE_SSH_COMMAND=$(get_config "su.${SU_NAME}.sshCommand")
if (( $? != 0 )); then
CORE_SSH_COMMAND=
fi
GIT_SSH_COMMAND="$CORE_SSH_COMMAND" git "$@" && (cd "$(extract_repo_dir "$@")" && apply_su "$SU_NAME")
}
su_git_inrepo_cmd() {
local SU_NAME=$1
shift
apply_su "$SU_NAME" && git "$@"
}
if [[ $# == 1 ]]; then
if [[ "$1" == "-l" ]] || [[ "$1" == "--list" ]]; then
print_su_list
else
apply_su "$SU_NAME"
fi
else
su_git "$@"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment