Skip to content

Commit c48da3a

Browse files
Copilotmrjf
andauthored
Fast-forward autoloop branches when ahead=0 instead of merging
Agent-Logs-Url: https://github.com/githubnext/tsessebe/sessions/fd8b9575-c039-4e3a-ad47-adf60b149480 Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
1 parent 1a66522 commit c48da3a

3 files changed

Lines changed: 91 additions & 6 deletions

File tree

.github/workflows/autoloop.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,35 @@ Each run executes **one iteration for the single selected program**:
378378
- Program `build-tsb-pandas-typescript-migration` → branch `autoloop/build-tsb-pandas-typescript-migration`
379379

380380
```bash
381-
git fetch origin
381+
git fetch origin main
382382
if git ls-remote --exit-code origin autoloop/{program-name}; then
383-
# Branch exists — check it out and merge the default branch
384-
git checkout -b autoloop/{program-name} origin/autoloop/{program-name}
385-
git merge origin/main --no-edit -m "Merge main into autoloop/{program-name}"
383+
# Branch exists — fetch it too so the ahead/behind counts below are
384+
# computed against up-to-date local copies of the remote tips.
385+
git fetch origin autoloop/{program-name}
386+
387+
ahead=$(git rev-list --count origin/main..origin/autoloop/{program-name})
388+
behind=$(git rev-list --count origin/autoloop/{program-name}..origin/main)
389+
390+
if [ "$ahead" = "0" ] && [ "$behind" != "0" ]; then
391+
# All of the branch's commits are already in main (typical case after a
392+
# successful merge of the previous iteration's PR). A merge here would
393+
# produce a noisy "Merge main into branch" commit that re-exposes every
394+
# historical file as a patch touch — the failure mode that triggers
395+
# gh-aw's E003 (>100 files) when a new PR is opened. Fast-forward the
396+
# canonical branch to main instead. This is lossless because ahead=0
397+
# proves every commit on the branch is already reachable from main.
398+
git checkout -B autoloop/{program-name} origin/main
399+
git push --force-with-lease origin autoloop/{program-name}
400+
elif [ "$ahead" != "0" ] && [ "$behind" != "0" ]; then
401+
# True divergence: branch has unique commits AND main has moved on.
402+
# Merge main into the branch so the iteration builds on the latest code.
403+
git checkout -B autoloop/{program-name} origin/autoloop/{program-name}
404+
git merge origin/main --no-edit -m "Merge main into autoloop/{program-name}"
405+
else
406+
# Already at main (ahead=0, behind=0) or only ahead of main (ahead>0,
407+
# behind=0). Nothing to merge — just check out the branch.
408+
git checkout -B autoloop/{program-name} origin/autoloop/{program-name}
409+
fi
386410
else
387411
# Branch does not exist — create it from the default branch
388412
git checkout -b autoloop/{program-name} origin/main

.github/workflows/sync-branches.lock.yml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/sync-branches.md

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,68 @@ steps:
8282
failed.append(branch)
8383
continue
8484
85-
# Merge the default branch into the program branch
85+
# Determine whether the branch can be fast-forwarded to the default
86+
# branch (ahead=0) or has truly diverged and needs a merge.
87+
ahead_proc = subprocess.run(
88+
["git", "rev-list", "--count", f"origin/{default_branch}..origin/{branch}"],
89+
capture_output=True, text=True,
90+
)
91+
behind_proc = subprocess.run(
92+
["git", "rev-list", "--count", f"origin/{branch}..origin/{default_branch}"],
93+
capture_output=True, text=True,
94+
)
95+
if ahead_proc.returncode != 0 or behind_proc.returncode != 0:
96+
# Don't guess — a failed rev-list with empty stdout would
97+
# otherwise be parsed as 0 below and could trigger an
98+
# incorrect fast-forward that loses commits.
99+
print(f" Failed to compute ahead/behind for {branch}: "
100+
f"ahead.rc={ahead_proc.returncode} stderr={ahead_proc.stderr.strip()!r} "
101+
f"behind.rc={behind_proc.returncode} stderr={behind_proc.stderr.strip()!r}")
102+
failed.append(branch)
103+
continue
104+
try:
105+
ahead = int(ahead_proc.stdout.strip())
106+
behind = int(behind_proc.stdout.strip())
107+
except ValueError:
108+
print(f" Failed to parse ahead/behind counts for {branch}: "
109+
f"ahead={ahead_proc.stdout!r} behind={behind_proc.stdout!r}")
110+
failed.append(branch)
111+
continue
112+
113+
if behind == 0:
114+
# Branch already contains every commit on the default branch.
115+
print(f" {branch} is already up to date with {default_branch} (ahead={ahead}, behind=0)")
116+
continue
117+
118+
if ahead == 0:
119+
# Lossless fast-forward: every commit on the branch is already
120+
# reachable from the default branch (typical case once the
121+
# previous iteration's PR has been merged). A real merge here
122+
# would create a "Merge default into branch" commit that re-
123+
# exposes every historical file as a patch touch — the noise
124+
# that trips gh-aw's MAX_FILES limit when the next iteration
125+
# opens a new PR. Reset the branch to the default branch's HEAD
126+
# and force-push (with lease) instead.
127+
reset = subprocess.run(
128+
["git", "reset", "--hard", f"origin/{default_branch}"],
129+
capture_output=True, text=True,
130+
)
131+
if reset.returncode != 0:
132+
print(f" Failed to fast-forward {branch}: {reset.stderr}")
133+
failed.append(branch)
134+
continue
135+
push = subprocess.run(
136+
["git", "push", "--force-with-lease", "origin", branch],
137+
capture_output=True, text=True,
138+
)
139+
if push.returncode != 0:
140+
print(f" Failed to push fast-forward of {branch}: {push.stderr}")
141+
failed.append(branch)
142+
continue
143+
print(f" Fast-forwarded {branch} to {default_branch} (was behind by {behind})")
144+
continue
145+
146+
# True divergence (ahead>0 and behind>0): merge the default branch in.
86147
merge = subprocess.run(
87148
["git", "merge", f"origin/{default_branch}", "--no-edit",
88149
"-m", f"Merge {default_branch} into {branch}"],

0 commit comments

Comments
 (0)