aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-13 21:19:22 +0000
committertv <tv@krebsco.de>2026-11-13 22:20:36 +0100
commit169da64fa4b444844e7257416b53c156094c0e44 (patch)
tree2acb338f21ff4a201a34fb2c34c1457d354b36e0
parent21c791e7c0b91ad984d1205d70398e426f7517d7 (diff)
populate: let git sources keep hooks, refuse them only for git+file:
git sources refused work trees with hooks, but populate's Git doesn't run hooks, so git-foreign's work tree with a hook is fine to use, as it expects. Only Nix's Git runs them, in a git+file: flake, so drawing inputs refers to a work tree with hooks as path: instead.
-rw-r--r--CHANGELOG.md8
-rw-r--r--README.md13
-rw-r--r--pkgs/populate/src/sh.rs29
3 files changed, 24 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 242bca3..2090a06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,11 +8,11 @@
and the other functions keep their arguments.
- Git can't take a `git` source's `url` or `ref`, or a `pass` source's
`name`, for an option.
-- `git` sources also refuse work trees whose `.git` directory contains
- hooks, or in which a submodule's `.git` isn't a file naming a repository
- in `.git/modules`, unless `reclone` is set.
+- `git` sources also refuse work trees in which a submodule's `.git` isn't
+ a file naming a repository in `.git/modules`, unless `reclone` is set.
- Drawing inputs refers to a source in a Git work tree as `git+file:` only
- if a `git` source would use its `.git` directory, and else as `path:`.
+ if a `git` source would use its `.git` directory, and it has no hooks,
+ and else as `path:`.
- `git` sources with a branch or tag as `ref` follow it: populate fetches
the branch or tag on every run, and resets the work tree to what it
fetched.
diff --git a/README.md b/README.md
index 94568f6..8b0a5d0 100644
--- a/README.md
+++ b/README.md
@@ -333,10 +333,9 @@ everything else. It doesn't change or remove anything outside:
`git` source as well.
* A `git` source only uses a work tree whose `.git` directory contains no
- symlinks, no `commondir` file, no linked work trees, and no hooks, and
- only the configuration that `git clone` and populate write, and in which
- each `.git` of a submodule is a file naming a repository in
- `.git/modules`. Otherwise Git's
+ symlinks, no `commondir` file and no linked work trees, and only the
+ configuration that `git clone` and populate write, and in which each
+ `.git` of a submodule is a file naming a repository in `.git/modules`. Otherwise Git's
commands could change what's elsewhere, or run commands, so populating
fails, telling what's wrong, unless the source's `reclone` is set. Git
runs no hooks.
@@ -725,9 +724,9 @@ automatically.
Sources in a Git work tree are referred to as `git+file:` (with submodules if
there are any), all other sources as `path:`, with symlinks resolved. Nix
-runs Git in a `git+file:` flake, so that's only for work trees whose `.git`
-directory a `git` source would use, see
-[The target directory](#the-target-directory). Lock
+runs Git in a `git+file:` flake, with its configuration and hooks, so
+that's only for work trees whose `.git` directory a `git` source would use,
+see [The target directory](#the-target-directory), and has no hooks. Lock
files get rewritten or generated on every run, so they match the sources.
Copies of `flake` and `flake-input` sources get made again only if the
delivered store path, the patches, or the sources they draw inputs from
diff --git a/pkgs/populate/src/sh.rs b/pkgs/populate/src/sh.rs
index 9daa60b..70efd3f 100644
--- a/pkgs/populate/src/sh.rs
+++ b/pkgs/populate/src/sh.rs
@@ -244,10 +244,10 @@ 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, 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
+/// 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. Hooks don't matter: populate's Git doesn't run them. 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() (
@@ -267,13 +267,6 @@ 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
@@ -813,9 +806,10 @@ use_state "$@"
/// resolve PATH...: prints, for each PATH, what's there and where it
/// resolves to, as two fields, each ending in a null byte. The first
/// holds d if PATH is a directory, g if it has a .git directory that
- /// git_problems finds nothing wrong with, s if it has .gitmodules, and
- /// f if it has flake.nix. Nix runs Git in a git+file: flake, with the
- /// repository's configuration and hooks, so it only gets such ones.
+ /// git_problems finds nothing wrong with, and that has no hooks, s if
+ /// it has .gitmodules, and f if it has flake.nix. Nix runs Git in a
+ /// git+file: flake, with the repository's configuration and hooks, so
+ /// it only gets such ones.
pub const RESOLVE: &str = r#"
for path; do
resolved=$(readlink -f "$path") || resolved=
@@ -823,7 +817,12 @@ for path; do
if test -d "$path"; then flags=${flags}d; fi
if ! test -L "$path"/.git && test -d "$path"/.git; then
problems=$(git_problems "$path" 2>/dev/null) || problems=failed
- if test -z "$problems"; then flags=${flags}g; fi
+ if test -d "$path"/.git/hooks; then
+ hooks=$(find "$path"/.git/hooks -mindepth 1 ! -name '*.sample' | head -n 1)
+ else
+ hooks=
+ fi
+ if test -z "$problems" && test -z "$hooks"; then flags=${flags}g; fi
fi
if test -e "$path"/.gitmodules; then flags=${flags}s; fi
if test -e "$path"/flake.nix; then flags=${flags}f; fi