]> quire.kejadlen.dev Git - quire.git/commitdiff
Canonicalize GIT_DIR in hook before resolving repo
authorAlpha Chen <alpha@kejadlen.dev>
Mon, 27 Apr 2026 16:36:07 +0000 (16:36 +0000)
committerAlpha Chen <alpha@kejadlen.dev>
Mon, 27 Apr 2026 16:46:15 +0000 (09:46 -0700)
git sets GIT_DIR to "." when invoking hooks via hook.<name>.command.
The repo resolver strips a prefix to find the repo name, so a relative
path fails the prefix check. Canonicalize in the hook so the resolver
gets an absolute path.

Assisted-by: GLM-5.1 via pi
src/bin/quire/commands/hook.rs

index 1c1cf17c48b478c7ed6e15dfeb3e55cdc6f8de6c..c9f9f9fbd7e008e2efb8d63a03ace84efe355c90 100644 (file)
@@ -1,7 +1,6 @@
 use std::io::{self, IsTerminal};
-use std::path::PathBuf;
 
-use miette::{Context, Result, bail, ensure, miette};
+use miette::{Context, IntoDiagnostic, Result, bail, ensure, miette};
 use quire::Quire;
 
 #[derive(Clone, Copy, Debug, clap::ValueEnum)]
@@ -32,10 +31,17 @@ fn post_receive(quire: &Quire) -> Result<()> {
         bail!("quire hook is for git to invoke, not for direct CLI use");
     }
 
-    // GIT_DIR is set by git when running hooks in bare repos.
+    // GIT_DIR is set by git when running hooks in bare repos. When hooks
+    // are invoked via hook.<name>.command, GIT_DIR may be relative (e.g.
+    // "."), so canonicalize before resolving.
     let git_dir = std::env::var("GIT_DIR")
-        .map(PathBuf::from)
-        .map_err(|e| miette!("GIT_DIR not set — hook must run inside a bare repo: {e}"))?;
+        .map_err(|e| miette!("GIT_DIR not set — hook must run inside a bare repo: {e}"))
+        .and_then(|git_dir| {
+            std::path::Path::new(&git_dir)
+                .canonicalize()
+                .into_diagnostic()
+        })
+        .map_err(|e| miette!("failed to resolve GIT_DIR: {e}"))?;
 
     let repo = quire
         .repo_from_path(&git_dir)