Skip to content

lanes-edit.sh: the RECOVERY "re-run lanes-edit.sh commit" cannot publish an edit that is already committed — on a clean tree commit returns before the push #194

Closed

Description

@brettheap

What happens

commit_push can't push when a peer's uncommitted file blocks pull --rebase (the dirty_elsewhere branch). After six attempts it exits 3 and prints this (lanes-edit.sh:2087-2090 at f87fd5a6):

RECOVERY: their author commits those files (a handoff: handoff(<lane>@<workstation>): <what>),
  then re-run: LANES_LANE=<lane> lanes-edit.sh commit "<what you wrote>"  — your edit is already
  a local commit here: git -C $LANES_REPO log --oneline origin/$LANES_BRANCH..HEAD
could not push origin/main: behind the remote, and a peer's uncommitted file blocks the rebase. Nothing was lost — your commit is local.

refuse_dirty_checkout gives the same advice at :1800-1801.

The re-run can't publish anything. The edit is already a local commit, so once the peer commits its file the register is clean. commit → commit_push then stages nothing and returns 0 before it reaches the push loop (:2022-2025):

if git -C "$LANES_REPO" -c "$CP_EXACT" diff --cached --quiet -- "${CP_PATHS[@]}"; then
  note "nothing staged for ${CP_PATHS[*]} — no commit made"
  return 0
fi

So the printed recovery exits 0 and pushes nothing. The stranded commit stays local until some later write from that checkout happens to carry it: the dangling commit the comment block at :2120-2148 describes. (This was established by reading the code at f87fd5a6, not by running the re-run. With a clean register the path is unambiguous.)

Observed, 2026-10-09 (lane opsXfactory-3, Eagle)

After an account swap, lane-start wrote five lanes' stamps into the shared runtime kit /workspace/projects/brett-wip-runtime-opsxfactory-team03a-20261008.

  • What was stranded. Lane opsXfactory-3's handoff stamp f680442fc and its row-state commit d51123aa2 stayed local, along with two other lanes' stamps. Two peers' unstaged handoff stamps blocked them, and the helper printed the RECOVERY above.
  • The peers' part. One peer committed its file in the kit (2e1e79e11). The other restored its own path and published from a private clone. That left the kit clean, so the printed re-run would have been a no-op.
  • The next real write would have failed too. d51123aa2 changes lane opsXfactory-3's row (lanes/LANES.md:123). Meanwhile origin had changed the ADJACENT row, lane opsXfactory-1's (:124), and git merges edits to adjacent lines as one conflict. A dry-run rebase in a private clone confirmed CONFLICT (content): Merge conflict in lanes/LANES.md on d51123aa2.
  • The conflict recovery would have lost a peer's work. The recovery printed for that conflict (:2149-2157) ends in git reset --hard origin/$LANES_BRANCH. In the shared kit that would also have dropped the peer's unpushed 2e1e79e11: its content was not on origin, and git cherry printed + for it.
  • What published it. Brett Heap's word was: "Do not reset, stash, or overwrite peer work."
    1. Take the helper's own lock (mkdir lanes/.lanes-edit.lock plus a pid file).
    2. git rebase --no-autostash origin/main.
    3. At the stop on the lane's own row commit: git checkout --ours -- lanes/LANES.md, then re-apply only that row's exact old→new line (refused unless upstream still held the old line), then git rebase --continue.
    4. Release the lock, then make one real helper write (log NOTED). Its pull --rebase and push carried the queue.
  • Result on brett-wip origin: 63a64ac7f, 90cc4a61b, the peer's 11ed5e874 and NOTED 1dbd72f65, one copy each. The two stamps already on origin dropped out, one by patch-id and one as empty.

Proposed remedy

  1. Make the recovery real. Preferred: when nothing is staged but origin/$LANES_BRANCH..HEAD is non-empty, commit (or a new publish subcommand) goes on to the push loop. That keeps the lock, the dirty-elsewhere guard and the retries. At minimum, change both RECOVERY texts to name a command that actually pushes.
  2. Row-edit conflicts. Suppose the rebase stops on a commit whose only LANES.md change is one row, and the conflict is with a different row's edit. The resolution is then mechanical: take upstream and re-apply that one old→new row line, refusing if upstream's copy of the row is no longer the old line. That is the row analogue of lanes-edit.sh: the Rule 6 line is appended at the end of LANES.md, so two lanes writing at once conflict on rebase and the lander must run the four-step RECOVERY by hand — resolve an append-only conflict as the union #145's append-only union.
  3. At minimum, warn. The conflict RECOVERY should say that reset --hard drops every unpushed local commit in the checkout, including peers' commits in a shared kit. It should also run git cherry for each such commit, not only the caller's own.

Related: #145 (append-only Rule 6 lines conflicting on rebase) and #127 (the direct-push path when another tracked file is dirty).

Lane: opsXfactory-3

Activity

  1. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-11T16:30:29Z, for #194

    Logged in lanes/log/openRepoTools-4.md at 5a6a3758e44f64799b7d9a246e14c8be1ab9d9af.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoTools#194:
       none
    2. `gh pr list --repo opensoft/openRepoTools --state all --search "#194"`, kept where the row or its body names `#194`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoTools` branches naming `194` as a whole token:
       none
    
  2. added 3 commits that reference this issue on Oct 13, 2026
  3. brettheap commented on Oct 19, 2026

    @brettheap
    ContributorAuthor

    RELEASED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-19T11:59:04Z, for #194 — #194 is closed by PR #214 (9b94a59); lane 4's claim ends

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions