commit f62f4dbd6dabaf7e889714f60d48ea3fa8696e47
parent f16259717222a423c2725e58d318c2ee19c358a4
Author: Louis Burda <quent.burda@gmail.com>
Date: Fri, 10 May 2024 00:25:31 +0200
Enhanced version
Store repositories in .subgit such that they are not tracked
Diffstat:
6 files changed, 155 insertions(+), 27 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,9 +2,11 @@ DESTDIR ?=
PREFIX ?= /usr/local
BINDIR ?= /bin
+BINS = subgit subgit-run subgit-init subgit-write subgit-clone
+
all:
install:
- install -m755 subgit subgit-clone -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
+ install -m755 $(BINS) -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
.PHONY: install all
diff --git a/subgit b/subgit
@@ -2,20 +2,17 @@
set -e
-# Find parent .subgit directory.
-path=$PWD
-while [ 1 ]; do
- [ -d "$path/.subgit" ] && break
- path=$(dirname "$path")
- if [ "$path" = "/" ]; then
- echo "No subgit found" 1>&2
- exit 1
- fi
-done
+if [ "$1" = "-C" ]; then
+ cd "$2"
+ shift
+ shift
+fi
-# Create a temporary symlink.
-trap 'unlink "$path/.git"' EXIT
-ln -sf ".subgit" "$path/.git"
+cmd="$1"
+shift
-# Proxy the command.
-git "$@"
+if [ "$cmd" = "--" ]; then
+ cmd="run"
+fi
+
+exec "subgit-$cmd" "$@"
diff --git a/subgit-clone b/subgit-clone
@@ -1,21 +1,41 @@
-#!/bin/sh
+#!/bin/bash
-set -e
+set -xe
-if [ $# -lt 2 ]; then
- echo "Usage: subgit-clone OPT.. REMOTE PATH"
+die() {
+ echo "$@" 2>&1
exit 1
+}
+
+[ $# -lt 2 ] && die "Usage: subgit-clone OPT.. REMOTE PATH"
+
+repo=$(realpath "$(git rev-parse --show-toplevel)")
+subrepo=$(realpath "${@: -1}")
+subrepo=${subrepo#$repo/}
+
+[ ! -z "$subrepo" -a "$subrepo" != "/" ]
+
+if [ -e "$repo/.subgitrc" ]; then
+ source "$repo/.subgitrc"
+else
+ declare -A subgit subgitinfo
fi
-path=${@: -1}
+[ -e "$repo/$subrepo" ] && die "Subrepo $subrepo already exists"
+#trap '[ ! -z "$repo" -a ! -z "$subrepo" ] && rm -rf "$repo/$subrepo"' exit
+trap 'echo "$repo/$subrepo"' exit
git clone "$@"
+[ ! -e "$repo/$subrepo" ] && die "Subrepo $subrepo missing"
+
+subgit[$subrepo]=1
+subgitinfo[$subrepo/remote]=$(git -C "$repo/$subrepo" remote get-url origin)
+subgitinfo[$subrepo/branch]=$(git -C "$repo/$subrepo" branch --show-current)
+subgitinfo[$subrepo/commit]=$(git -C "$repo/$subrepo" rev-parse --verify HEAD)
-echo "remote=$(git -C "$path" remote get-url origin)" > "$path/.subgitrc"
-echo "branch=$(git -C "$path" branch --show-current)" >> "$path/.subgitrc"
-echo "commit=$(git -C "$path" rev-parse --verify HEAD)" >> "$path/.subgitrc"
+source subgit-write
-mv "$path/.git" "$path/.subgit"
+mkdir -p $(dirname "$repo/.subgit/$subrepo")
+mv "$repo/$subrepo/.git" "$repo/.subgit/$subrepo"
-[ ! -f "$path/.gitignore" ] && echo "/.gitignore" >> "$path/.gitignore"
-echo "/.subgit" >> "$path/.gitignore"
+trap - exit
diff --git a/subgit-init b/subgit-init
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+set -xe
+
+die() {
+ echo "$@" 2>&1
+ exit 1
+}
+
+recursive=0
+update=0
+while [ $# -ge 1 ]; do
+ if [ "$1" = "-r" ]; then
+ recursive=1
+ shift
+ elif [ "$1" = "-u" ]; then
+ update=1
+ shift
+ else
+ die "Unknown opt: $1"
+ fi
+done
+
+[ $# -ne 0 ] && die "Usage: subgit-init"
+
+repo=$(realpath "$(git rev-parse --show-toplevel)")
+source "$repo/.subgitrc"
+
+for subrepo in ${!subgit[@]}; do
+ path="$repo/.subgit/$subrepo"
+ if [ ! -d "$path" ]; then
+ mkdir -p "$(dirname "$path")"
+ git clone --bare --single-branch -b "${subgitinfo[$subrepo/branch]}" \
+ "${subgitinfo[$subrepo/remote]}" "$path"
+ git -C "$path" config --local --bool core.bare false
+ fi
+ [ -d "$repo/$subrepo" ] || mkdir -p "$repo/$subrepo"
+ subgit -C "$repo/$subrepo" -- git checkout "${subgitinfo[$subrepo/branch]}"
+ if [ $update -ne 0 ]; then
+ subgitinfo[$subrepo/remote]=$(git -C "$path" remote get-url origin)
+ subgitinfo[$subrepo/branch]=$(git -C "$path" branch --show-current)
+ subgitinfo[$subrepo/commit]=$(git -C "$path" rev-parse --verify HEAD)
+ fi
+ subgit -C "$repo/$subrepo" -- git reset "${subgitinfo[$subrepo/commit]}"
+ if [ $recursive -ne 0 -a -e "$repo/$subrepo/.subgitrc" ]; then
+ subgit -C "$repo/$subrepo" -- subgit-init
+ fi
+done
+
+source subgit-write
diff --git a/subgit-run b/subgit-run
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+set -e
+
+die() {
+ echo "$@" 1>&2
+ exit 1
+}
+
+if [ "$1" = "-C" ]; then
+ cd "$2"
+ shift
+ shift
+fi
+
+repo=$(realpath "$(git rev-parse --show-toplevel)")
+[ "${PWD#$repo/}" != "$PWD" ] || die "Bad path $repo > $PWD"
+
+path=$PWD
+while [ 1 ]; do
+ relpath=${path#$repo/}
+ [ -d "$repo/.subgit/$relpath" ] && break
+ path=$(dirname "$path")
+ echo "$path"
+ [ "$path" = "$repo" ] && die "No subgit found"
+done
+
+trap 'unlink "$path/.git"' EXIT
+ln -sf "$repo/.subgit/$relpath" "$path/.git"
+
+"$@"
diff --git a/subgit-write b/subgit-write
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+subgit-write-inner() {
+ set -e
+
+ repo=$(realpath "$(git rev-parse --show-toplevel)")
+
+ echo -e "#!/bin/bash\n" > "$repo/.subgitrc"
+ echo -e "declare -A subgit subgitinfo\n" >> "$repo/.subgitrc"
+
+ for subrepo in ${!subgit[@]}; do
+ echo "subgit[$subrepo]=1"
+ echo "subgitinfo[$subrepo/remote]='${subgitinfo[$subrepo/remote]}'"
+ echo "subgitinfo[$subrepo/branch]='${subgitinfo[$subrepo/branch]}'"
+ echo "subgitinfo[$subrepo/commit]='${subgitinfo[$subrepo/commit]}'"
+ echo ""
+ done >> "$repo/.subgitrc"
+
+ if [ ! -e "$repo/.gitignore" ]; then
+ echo "/.gitignore" > "$repo/.gitignore"
+ fi
+ cat "$repo/.gitignore" | grep -q "^/.subgit$" \
+ || echo "/.subgit" >> "$repo/.gitignore"
+}
+
+( subgit-write-inner "$@"; )
+
+unset subgit-write-inner