Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions scripts/check_roadmap_diff_additive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,16 @@ EOF
*"never the tree against itself"*) printf 'ok row %-2s push shape, parent not fetched (depth-1): refused by name, never HEAD itself\n' "$row" ;;
*) printf 'FAIL row %-2s push shape, parent not fetched: refused for the wrong reason (rc=%s): %s\n' "$row" "$rc5" "$err5"; fails=1 ;;
esac
# Push shape, HEAD BEHIND the tip: a later merge landed before this run checked out, so
# merge-base(origin/main, HEAD) is HEAD itself (run 34747052599, main red 2026-09-13). The base
# is still HEAD's first parent; without this row the resolver named HEAD and the run was refused.
row=$((row + 1))
rm -rf "${R:?}.behind"; git clone -q "file://$R" "$R.behind" 2>/dev/null
( cd "$R.behind" && git checkout -q main && prev=$(git rev-parse HEAD) && cp "$TD/base_dup.yaml" later.yaml && git add later.yaml && git -c user.name=t -c user.email=t@t commit -qm later-merge && git update-ref refs/remotes/origin/main HEAD && git checkout -q --detach "$prev" ) 2>/dev/null
got6=$( cd "$R.behind" && bash -c '. "$0" --lib-only; REPO_ROOT="$1"; resolve_base HEAD && printf "%s|%s" "$BASE_REF" "$BASE_HOW"' "$SELF" "$R.behind" 2>/dev/null ) || true
want6=$( cd "$R.behind" && git rev-parse 'HEAD^1' )
case "$got6" in "$want6|first parent of HEAD (HEAD is on origin/main, behind the tip"*) printf 'ok row %-2s push shape, HEAD behind the tip (a later merge landed first) -> its first parent, never HEAD itself\n' "$row" ;;
*) printf 'FAIL row %-2s push shape, HEAD behind the tip: wanted %s|first parent of HEAD (HEAD is on origin/main, behind the tip..., got %s\n' "$row" "$want6" "$got6"; fails=1 ;; esac
# Rows 19-20: a STACKED merge-group entry at depth 1 — the head's single parent
# is the previous entry's squash, not the origin/main tip. Under merge_group it
# deepens and names that parent; with deepening disabled (the mutation) it is
Expand Down
22 changes: 17 additions & 5 deletions scripts/lib/resolve_base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@ resolve_base() {
local PROG="${PROG:-resolve_base}"
headid=$(git -C "$REPO_ROOT" rev-parse "$head^{commit}" 2>/dev/null || true)
main_tip=$(git -C "$REPO_ROOT" rev-parse origin/main 2>/dev/null || true)
if [ -n "$headid" ] && [ "$headid" = "$main_tip" ]; then
# push shape: HEAD IS the origin/main tip. merge-base(origin/main, HEAD) is HEAD, and a
# differential of HEAD against itself passes vacuously. The change under judgment is
# what the tip's first parent lacks; a depth-1 checkout must deepen by one to hold it.
# push shape: HEAD is ON origin/main -- the tip, or a commit BEHIND the tip when a later merge
# landed before this run checked out (run 34747052599: origin/main had moved one squash past
# HEAD; merge-base(origin/main, HEAD) was HEAD itself and the run was refused "never the tree
# against itself"). Either way merge-base is HEAD and a differential of HEAD against itself
# passes vacuously. The change under judgment is what the first parent lacks; a depth-1
# checkout must deepen by one to hold it.
local on_main=0
if [ -n "$headid" ] && [ -n "$main_tip" ]; then
# On main's FIRST-PARENT line, not merely an ancestor: a feature commit merged into main is an
# ancestor too, and its base is the merge-base, not its own parent (case-table row 15).
if [ "$headid" = "$main_tip" ] || git -C "$REPO_ROOT" rev-list --first-parent "$main_tip" 2>/dev/null | grep -qx "$headid"; then on_main=1; fi
fi
if [ "$on_main" = 1 ]; then
local p; p=$(git -C "$REPO_ROOT" rev-parse -q --verify "$head^1^{commit}" 2>/dev/null || true)
if [ -n "$p" ]; then BASE_REF="$p"; BASE_HOW="first parent of $head (HEAD is the origin/main tip: push shape)"; return 0; fi
if [ -n "$p" ]; then
if [ "$headid" = "$main_tip" ]; then BASE_HOW="first parent of $head (HEAD is the origin/main tip: push shape)"; else BASE_HOW="first parent of $head (HEAD is on origin/main, behind the tip: push shape, a later merge landed first)"; fi
BASE_REF="$p"; return 0
fi
printf '%s: %s is the origin/main tip and its first parent is not fetched, so the only base would be %s itself; refused (never the tree against itself). Deepen the checkout: git fetch --deepen=1 origin +refs/heads/main:refs/remotes/origin/main\n' "$PROG" "$head" "$head" >&2
return 1
fi
Expand Down
Loading