jw-pkg/scripts/pgit.sh
Jan Lindemann 1e9ab195a6 pgit.sh: Pass --autostash to rebase
Calling make git-pull-xxx from a projects directory stops iterating
projects if one has a dirty workspace. Calling --autostash fixes
that.

With this in place, a failed rebase leaves the local changes behind
stashed. So, after manually fixing the rebase, the stash needs to be
manually reapplied. The commands that led up to the failure are
logged right before, so I have hope that this is learnable, and not
too much of a footgun.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-10 09:55:59 +01:00

264 lines
5.5 KiB
Bash

#!/bin/sh
log()
{
echo $@
}
err()
{
log $@
}
fatal()
{
err $@
exit 1
}
marker()
{
log "# ------------- [$cur/$n_projects] $@"
}
fat_marker()
{
log "# ==================================================== [$cur/$n_projects] $@"
}
config()
{
[ "$pdir" ] || {
# guess pdir
pdir=`pwd`
while [ ! -r Makefile ] || ! grep -q some-random-string-to-id-this-makefile Makefile; do
[ "$pdir" = / ] && fatal "didn't find \"proj\" in directory components"
pdir=`dirname $pdir`
done
}
[ "$pdirs" ] || {
pdirs=`(cd $pdir; ls -d */.git 2>/dev/null | sed 's%/.git%%')`
}
n_projects=`echo $pdirs | wc -w`
}
run_git()
{
marker git "$@"
git "$@"
}
# ------------- commands
run()
{(
local cmd=$1
local d
shift
config
cd $pdir
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
for d in $pdirs; do
cur=`expr $cur + 1`
run_git -C $d $cmd "$@"
done
)}
commit()
{(
local d do_cvs
if [ "$1" = --cvs ]; then
do_cvs=true
shift
fi
config
cd $pdir
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
for d in $pdirs; do
cur=`expr $cur + 1`
if run_git -C $d diff-index --quiet HEAD --; then
log "Nothing to commit"
continue
fi
run_git -C $d commit "$@"
done
)}
clone()
{(
run_clone() {
local url="$1"
local p="$2"
run_git $GIT_GLOBAL_OPTS clone "$url" "$p"
if [[ "$GIT_GLOBAL_OPTS" =~ proactiveAuth ]]; then
run_git -C $p config set http.proactiveAuth basic
fi
}
local remote_base="$global_remote_base"
local remote_subpath="$global_remote_subpath"
local p
local whoami="$(id -un)"
config
cd $pdir
local projects="$PGIT_CLONE_PROJECTS"
local ignore="$PGIT_IGNORE"
local thisdir="${0%/*}"
local jw_projects="/usr/bin/python3 $thisdir/jw-pkg.py"
local create_remote_user_repos=false
local long_opts="create-remote-user-repos"
local refspec=()
long_opts="$long_opts,refspec:"
local login="$whoami"
[ "$cmd_login" ] && login="$cmd_login"
local opts
opts=$(getopt -o C --long "$long_opts" -n clone -- "$@") || fatal "Failed to parse options $@"
eval set -- "$opts"
while [ "$1" != -- ]; do
case "$1" in
-C | --create-remote-user-repos)
create_remote_user_repos=true
;;
--refspec)
refspec=(${2//:/ })
shift
;;
*)
fatal "Unknown option $1"
;;
esac
shift
done
local fromuser="${refspec[0]}"
local fromref="${refspec[1]}"
local toref="${refspec[2]}"
[ "$fromuser" ] || fromuser=$whoami
[ "$fromref" ] || fromref=master
local git_srv_admin="$SSH $login@git.janware.com /opt/jw-pkg/bin/git-srv-admin.sh"
if [ -z "$projects" ]; then
projects=`$jw_projects projects list-repos --from-user $fromuser $remote_base`
[ "$?" != 0 ] && exit 1
fi
if [ "$login" ]; then
[ "${remote_base/@/}" = "${remote_base}" ] || fatal "Specified both --login $login and user in URL $remote_base"
remote_base=$(echo $remote_base | sed "s|://|://$login@|")
fi
n_projects=`echo $projects | wc -w`
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
for p in $projects; do
if echo $ignore | grep -q "\b$p\b"; then
continue
fi
cur=`expr $cur + 1`
local pullurl=$remote_base/$fromuser$remote_subpath/$p
local pushurl=$remote_base/$login$remote_subpath/$p
local curref=""
fat_marker "Fetching project $p from user $fromuser"
if [ "$fromuser" = "$login" ]; then
if [ -d $p ]; then
run_git -C $p pull --recurse-submodules=on-demand
run_git -C $p submodule foreach --recursive 'git fetch --tags -f origin'
else
run_clone $remote_base/$fromuser$remote_subpath/$p $p
fi
else
local remotename="jw-$fromuser"
if [ -d $p ]; then
run_git -C $p remote | grep -q "^$remotename$" || {
run_git -C $p remote add $remotename $pullurl
run_git -C $p remote set-url --push $remotename no_push
}
run_git -C $p fetch --prune --recurse-submodules=on-demand $remotename $fromref
run_git -C $p submodule foreach --recursive 'git fetch --tags -f origin'
if [ "$toref" ]; then
run_git -C $p rebase --autostash $remotename/$fromref $toref
run_git -C $p merge --ff-only $remotename/$fromref $toref
fi
else
# set -x
run_clone $remote_base/$fromuser$remote_subpath/$p $p
run_git -C $p remote rename origin $remotename || fatal failed to rename remote in $p
run_git -C $p remote set-url --push $remotename no_push
if [ $create_remote_user_repos = true ]; then
$git_srv_admin -u $login -j create-personal-project $p
run_git -C $p remote add origin $pushurl
run_git -C $p push --recurse-submodules=on-demand origin master
$git_srv_admin -u $login -j update-descriptions $p
run_git -C $p branch --set-upstream-to origin/master master
fi
fi
fi
run_git -C $p submodule update --init --recursive || fatal git submodule update failed in $p
done
)}
diff()
{(
local d
config
cd $pdir
for d in $pdirs; do
cur=`expr $cur + 1`
# marker $d
run_git -C $d diff --src-prefix=$d/ --dst-prefix=$d/ "$@"
done
)}
echo "running $0 $@ GIT_SSH=$GIT_SSH" >&2
cur=0
SSH=ssh
[ "$GIT_SSH" ] && SSH=$GIT_SSH
global_remote_base="ssh://git.janware.com/srv/git"
while [ "${1:0:1}" = - ]; do
case "$1" in
'--remote-base')
global_remote_base="$2"
shift
;;
esac
shift
done
# Only janware.com ssh git supports subdirectories below users
if [[ "$global_remote_base" =~ git.janware.com ]]; then
global_remote_subpath="/proj"
else
global_remote_subpath=""
fi
cmd=$1
shift
while [ "${1:0:1}" = - ]; do
case $1 in
'--login')
cmd_login="$2"
shift 2
;;
*)
break
;;
esac
done
case $cmd in
clone|diff|commit)
$cmd "$@"
;;
*)
run $cmd "$@"
;;
esac