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 42eda2d..b14be20 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,7 +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 +- **AND** parent submodule ignore settings do not hide or prevent staging the gitlink pointer update #### 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 86c7c84..822fca0 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 @@ -13,6 +13,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. +- [x] Stage the gitlink with `git update-index --cacheinfo` so registered submodule ignore settings cannot suppress the pointer update. ## 4. Cleanup diff --git a/scripts/agent-branch-finish.sh b/scripts/agent-branch-finish.sh index 58768bf..48e3ff6 100755 --- a/scripts/agent-branch-finish.sh +++ b/scripts/agent-branch-finish.sh @@ -519,7 +519,7 @@ maybe_auto_commit_parent_gitlink() { local gitlink_index_sha="" local gitlink_parent_head_sha="" local subrepo_head_sha="" - local add_output="" + local update_index_output="" local commit_output="" local commit_message="" @@ -563,21 +563,24 @@ maybe_auto_commit_parent_gitlink() { 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 + if [[ -z "$subrepo_head_sha" ]]; then return 0 fi - - if ! add_output="$(git -C "$super_root" add -- "$subrepo_rel" 2>&1)"; then - echo "[agent-branch-finish] Warning: parent gitlink staging failed for ${subrepo_rel} in ${super_root}." >&2 - [[ -n "$add_output" ]] && echo "$add_output" >&2 + if [[ -n "$gitlink_index_sha" && "$gitlink_index_sha" == "$gitlink_parent_head_sha" && "$gitlink_index_sha" == "$subrepo_head_sha" ]]; then return 0 fi - if 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 }')" - if [[ "$gitlink_index_sha" == "$gitlink_parent_head_sha" ]]; then + + if [[ "$gitlink_index_sha" != "$subrepo_head_sha" ]]; then + if ! update_index_output="$(git -C "$super_root" update-index --cacheinfo 160000 "$subrepo_head_sha" "$subrepo_rel" 2>&1)"; then + echo "[agent-branch-finish] Warning: parent gitlink staging failed for ${subrepo_rel} in ${super_root}." >&2 + [[ -n "$update_index_output" ]] && echo "$update_index_output" >&2 return 0 fi + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + fi + 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 commit_message="Update ${subrepo_rel} subrepo pointer" diff --git a/templates/scripts/agent-branch-finish.sh b/templates/scripts/agent-branch-finish.sh index 58768bf..48e3ff6 100755 --- a/templates/scripts/agent-branch-finish.sh +++ b/templates/scripts/agent-branch-finish.sh @@ -519,7 +519,7 @@ maybe_auto_commit_parent_gitlink() { local gitlink_index_sha="" local gitlink_parent_head_sha="" local subrepo_head_sha="" - local add_output="" + local update_index_output="" local commit_output="" local commit_message="" @@ -563,21 +563,24 @@ maybe_auto_commit_parent_gitlink() { 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 + if [[ -z "$subrepo_head_sha" ]]; then return 0 fi - - if ! add_output="$(git -C "$super_root" add -- "$subrepo_rel" 2>&1)"; then - echo "[agent-branch-finish] Warning: parent gitlink staging failed for ${subrepo_rel} in ${super_root}." >&2 - [[ -n "$add_output" ]] && echo "$add_output" >&2 + if [[ -n "$gitlink_index_sha" && "$gitlink_index_sha" == "$gitlink_parent_head_sha" && "$gitlink_index_sha" == "$subrepo_head_sha" ]]; then return 0 fi - if 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 }')" - if [[ "$gitlink_index_sha" == "$gitlink_parent_head_sha" ]]; then + + if [[ "$gitlink_index_sha" != "$subrepo_head_sha" ]]; then + if ! update_index_output="$(git -C "$super_root" update-index --cacheinfo 160000 "$subrepo_head_sha" "$subrepo_rel" 2>&1)"; then + echo "[agent-branch-finish] Warning: parent gitlink staging failed for ${subrepo_rel} in ${super_root}." >&2 + [[ -n "$update_index_output" ]] && echo "$update_index_output" >&2 return 0 fi + gitlink_index_sha="$(git -C "$super_root" ls-files -s -- "$subrepo_rel" | awk 'NR == 1 { print $2 }')" + fi + 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 commit_message="Update ${subrepo_rel} subrepo pointer" diff --git a/test/finish.test.js b/test/finish.test.js index 7263e64..37a600c 100644 --- a/test/finish.test.js +++ b/test/finish.test.js @@ -190,6 +190,8 @@ test('agent-branch-finish auto-commits parent gitlink after nested repo finish', 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); + result = runCmd('git', ['config', 'submodule.packages/child.ignore', '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);