From cc8344a124cb0ce5ee0d48b632d75c8d7b5bbff6 Mon Sep 17 00:00:00 2001 From: lg320531124 Date: Mon, 29 Jun 2026 17:41:40 +0800 Subject: [PATCH] fix(git): resolve canonical_root '..' components in worktree git_common_dir When git_common_dir is a relative path like '../.git', join_root_relative produces '/workspace/../.git'. After stripping '/.git', the result is '/workspace/..' which resolves to the PARENT directory instead of the workspace root. This caused detect_changes to return empty impacted_symbols because the path-prefix mismatch between git diff output and graph file paths. Add realpath() call after stripping '/.git' to resolve any remaining '..' components. Falls back to the un-resolved path if realpath fails (e.g. non-existent path during testing). Fixes #690, fixes #659 Signed-off-by: lg320531124 --- src/git/git_context.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/git/git_context.c b/src/git/git_context.c index 99ae17cf3..4e02091a5 100644 --- a/src/git/git_context.c +++ b/src/git/git_context.c @@ -2,6 +2,7 @@ #include "foundation/compat_fs.h" #include "foundation/constants.h" +#include "foundation/platform.h" #include "foundation/str_util.h" #include @@ -11,6 +12,11 @@ #include #include +/* realpath() is POSIX; on Windows use _fullpath (same semantics). */ +#ifdef _WIN32 +#define realpath(path, resolved) _fullpath(resolved, path, CBM_SZ_4K) +#endif + enum { GIT_CMD_MAX = 1024, GIT_OUTPUT_MAX = 4096, @@ -151,6 +157,19 @@ static char *derive_canonical_root(const char *worktree_root, const char *git_co } #endif + /* Normalize ".." components left by relative git_common_dir paths. + * E.g. "/workspace/../.git" → strip "/.git" → "/workspace/.." → "/", + * but the correct canonical root is "/workspace". Fixes #659/#690: + * detect_changes returned empty impacted_symbols because the + * path-prefix mismatch between git diff output and graph file paths. */ + cbm_normalize_path_sep(root); + char *resolved = realpath(root, NULL); + if (resolved) { + free(root); + return resolved; + } + /* realpath may fail if the path doesn't exist (e.g. during testing); + * fall back to the un-resolved path rather than returning NULL. */ return root; }