aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-13 20:27:48 +0000
committertv <tv@krebsco.de>2026-11-13 21:59:07 +0100
commitb34f53d538c5afa95fd0dc6dd81b56e4995b80c2 (patch)
treef8afac88dcb0a695f6eaf911fcdc7cdc36e62532 /pkgs
parentef581c93f391919b35b903b93af45f33d90de15d (diff)
populate: check the hooks and submodules of Git work trees
git submodule update uses the .git of a submodule as it finds it in the work tree: a repository of its own, with configuration that runs commands, or a file naming a repository elsewhere. So git_problems also requires each .git below the work tree to be a file naming a repository in .git/modules. And it refuses hooks in .git/hooks, which populate's Git doesn't run, but Nix's does, writing the lock file of a flake in a git source. git-submodule plants a submodule's .git in the work tree: a repository of its own whose configuration names a filter, and a file naming a repository elsewhere. The fixture withsub has gitsrc as its submodule sub.
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/populate/src/sh.rs36
1 files changed, 32 insertions, 4 deletions
diff --git a/pkgs/populate/src/sh.rs b/pkgs/populate/src/sh.rs
index ce42e12..f76a0f7 100644
--- a/pkgs/populate/src/sh.rs
+++ b/pkgs/populate/src/sh.rs
@@ -244,10 +244,11 @@ ln -fnsT "$2" "$1"
/// Defines git_problems PATH, which prints why populate can't use the .git
/// directory of the Git work tree at PATH, or nothing. A .git directory
/// that git clone and populate made has no symlinks, no commondir file,
-/// which names another repository, no linked work trees, and only the
-/// configuration they write: the repository's format, the remote, branches,
-/// and submodules, whose repositories have their work tree in the work
-/// tree.
+/// which names another repository, no linked work trees, no hooks, and only
+/// the configuration they write: the repository's format, the remote,
+/// branches, and submodules, whose repositories have their work tree in the
+/// work tree. And each .git below the work tree, which Git uses for a
+/// submodule there, is a file naming a repository in .git/modules.
pub const GIT_PROBLEMS: &str = r#"
git_problems() (
path=$1
@@ -266,6 +267,33 @@ git_problems() (
printf '%s has linked work trees' "$git_dir"
exit
fi
+ if test -d "$git_dir"/hooks; then
+ hooks=$(find "$git_dir"/hooks -mindepth 1 ! -name '*.sample' | head -n 3 | paste -s -d ' ' -)
+ if test -n "$hooks"; then
+ printf '%s contains hooks: %s' "$git_dir" "$hooks"
+ exit
+ fi
+ fi
+ nested=$(
+ find "$path" -path "$git_dir" -prune -o -name .git -exec sh -c '
+ modules=$1
+ shift
+ for git; do
+ if ! test -L "$git" && test -f "$git"; then
+ gitdir=$(sed -n "s/^gitdir: //p" "$git")
+ resolved=$(cd "${git%/.git}" && cd "$gitdir" 2>/dev/null && pwd -P) || :
+ case $resolved in
+ "$modules"/?*) continue ;;
+ esac
+ fi
+ printf "%s\n" "$git"
+ done
+ ' sh "$(cd "$git_dir" && pwd -P)/modules" {} + | head -n 1
+ )
+ if test -n "$nested"; then
+ printf '%s is not a file naming a repository in %s/modules' "$nested" "$git_dir"
+ exit
+ fi
find "$git_dir" -name config -type f | while IFS= read -r config; do
command git config --file "$config" --list --name-only |
while IFS= read -r key; do