From 86b7b1484aa5fd8ef56189c1a15b8af07bbdc650 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Thu, 23 Apr 2026 12:13:31 +0200 Subject: [PATCH] Detect parent gitlink drift even when submodules are ignored The first auto-commit path trusted parent git diff, but real parent workspaces can set diff.ignoreSubmodules=all. That hides exactly the gitlink drift this feature needs to commit, so detection now compares the parent gitlink index SHA to the nested repo HEAD and parent HEAD tree entry. Constraint: Parent workspaces may intentionally hide submodule noise in normal status output. Rejected: Disable diff.ignoreSubmodules temporarily | mutates parent repo configuration and still leaves hidden-index edge cases. Confidence: high Scope-risk: narrow Directive: Keep gitlink drift detection SHA-based; do not rely on git diff status for subrepo pointer updates. Tested: bash -n scripts/agent-branch-finish.sh; bash -n templates/scripts/agent-branch-finish.sh; node --test test/finish.test.js; openspec validate agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59 --strict; git diff --check Not-tested: Full npm test after follow-up; full suite passed before this narrow SHA-detection fix --- .../specs/finish/spec.md | 1 + .../tasks.md | 1 + scripts/agent-branch-finish.sh | 15 ++++++++++++--- templates/scripts/agent-branch-finish.sh | 15 ++++++++++++--- test/finish.test.js | 2 ++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/specs/finish/spec.md b/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/specs/finish/spec.md index 9226b67..42eda2d 100644 --- a/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/specs/finish/spec.md +++ b/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/specs/finish/spec.md @@ -10,6 +10,7 @@ After a successful nested repository finish, Guardex SHALL detect when the finis - **WHEN** `gx branch finish` merges the nested agent branch and fast-forwards the nested base worktree - **THEN** Guardex commits the parent repo gitlink path with a message naming that subrepo pointer - **AND** unrelated parent staged paths are not included in that commit +- **AND** parent `diff.ignoreSubmodules=all` settings do not hide the gitlink pointer update from this detection #### Scenario: Parent auto-commit is disabled diff --git a/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/tasks.md b/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/tasks.md index df23f8e..86c7c84 100644 --- a/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/tasks.md +++ b/openspec/changes/agent-codex-auto-commit-parent-subrepo-upgrades-2026-04-23-11-59/tasks.md @@ -12,6 +12,7 @@ - [x] Add parent gitlink detection and path-scoped parent commit to `agent-branch-finish`. - [x] Pass parent gitlink controls through `gx finish`. +- [x] Compare gitlink index SHA to nested HEAD so parent `diff.ignoreSubmodules=all` does not hide pointer upgrades. ## 4. Cleanup diff --git a/scripts/agent-branch-finish.sh b/scripts/agent-branch-finish.sh index ca7e40c..58768bf 100755 --- a/scripts/agent-branch-finish.sh +++ b/scripts/agent-branch-finish.sh @@ -516,6 +516,9 @@ maybe_auto_commit_parent_gitlink() { local super_root="" local subrepo_rel="" local gitlink_mode="" + local gitlink_index_sha="" + local gitlink_parent_head_sha="" + local subrepo_head_sha="" local add_output="" local commit_output="" local commit_message="" @@ -557,8 +560,10 @@ maybe_auto_commit_parent_gitlink() { if [[ "$gitlink_mode" != "160000" ]]; then return 0 fi - if git -C "$super_root" diff --quiet -- "$subrepo_rel" \ - && git -C "$super_root" diff --cached --quiet -- "$subrepo_rel"; then + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + gitlink_parent_head_sha="$(git -C "$super_root" ls-tree HEAD -- "$subrepo_rel" | awk 'NR == 1 { print $3 }')" + subrepo_head_sha="$(git -C "$repo_common_root" rev-parse HEAD 2>/dev/null || true)" + if [[ -n "$gitlink_index_sha" && "$gitlink_index_sha" == "$gitlink_parent_head_sha" && "$gitlink_index_sha" == "$subrepo_head_sha" ]]; then return 0 fi @@ -568,7 +573,11 @@ maybe_auto_commit_parent_gitlink() { return 0 fi if git -C "$super_root" diff --cached --quiet -- "$subrepo_rel"; then - return 0 + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + gitlink_parent_head_sha="$(git -C "$super_root" ls-tree HEAD -- "$subrepo_rel" | awk 'NR == 1 { print $3 }')" + if [[ "$gitlink_index_sha" == "$gitlink_parent_head_sha" ]]; then + return 0 + fi fi commit_message="Update ${subrepo_rel} subrepo pointer" diff --git a/templates/scripts/agent-branch-finish.sh b/templates/scripts/agent-branch-finish.sh index ca7e40c..58768bf 100755 --- a/templates/scripts/agent-branch-finish.sh +++ b/templates/scripts/agent-branch-finish.sh @@ -516,6 +516,9 @@ maybe_auto_commit_parent_gitlink() { local super_root="" local subrepo_rel="" local gitlink_mode="" + local gitlink_index_sha="" + local gitlink_parent_head_sha="" + local subrepo_head_sha="" local add_output="" local commit_output="" local commit_message="" @@ -557,8 +560,10 @@ maybe_auto_commit_parent_gitlink() { if [[ "$gitlink_mode" != "160000" ]]; then return 0 fi - if git -C "$super_root" diff --quiet -- "$subrepo_rel" \ - && git -C "$super_root" diff --cached --quiet -- "$subrepo_rel"; then + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + gitlink_parent_head_sha="$(git -C "$super_root" ls-tree HEAD -- "$subrepo_rel" | awk 'NR == 1 { print $3 }')" + subrepo_head_sha="$(git -C "$repo_common_root" rev-parse HEAD 2>/dev/null || true)" + if [[ -n "$gitlink_index_sha" && "$gitlink_index_sha" == "$gitlink_parent_head_sha" && "$gitlink_index_sha" == "$subrepo_head_sha" ]]; then return 0 fi @@ -568,7 +573,11 @@ maybe_auto_commit_parent_gitlink() { return 0 fi if git -C "$super_root" diff --cached --quiet -- "$subrepo_rel"; then - return 0 + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + gitlink_parent_head_sha="$(git -C "$super_root" ls-tree HEAD -- "$subrepo_rel" | awk 'NR == 1 { print $3 }')" + if [[ "$gitlink_index_sha" == "$gitlink_parent_head_sha" ]]; then + return 0 + fi fi commit_message="Update ${subrepo_rel} subrepo pointer" diff --git a/test/finish.test.js b/test/finish.test.js index 22b75c7..7263e64 100644 --- a/test/finish.test.js +++ b/test/finish.test.js @@ -188,6 +188,8 @@ test('agent-branch-finish auto-commits parent gitlink after nested repo finish', ALLOW_COMMIT_ON_PROTECTED_BRANCH: '1', }); assert.equal(result.status, 0, result.stderr || result.stdout); + result = runCmd('git', ['config', 'diff.ignoreSubmodules', 'all'], parentDir); + assert.equal(result.status, 0, result.stderr || result.stdout); fs.writeFileSync(path.join(parentDir, 'unrelated-parent.txt'), 'already staged\n', 'utf8'); result = runCmd('git', ['add', 'unrelated-parent.txt'], parentDir); assert.equal(result.status, 0, result.stderr || result.stdout);