mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 09:13:14 +00:00
96 lines
4.7 KiB
Markdown
96 lines
4.7 KiB
Markdown
|
|
# Cherry-picking upstream into the fork
|
||
|
|
|
||
|
|
This repository is a long-lived fork of `langchain-ai/open-swe` (git remote `upstream`).
|
||
|
|
Upstream changes are brought in one commit at a time with `git cherry-pick`, and every
|
||
|
|
diverged commit is tracked in a triage ledger so a decision is made once and not revisited.
|
||
|
|
`dev` is the integration branch; the broader strategy lives in the fork-maintenance section
|
||
|
|
of `CLAUDE.md`.
|
||
|
|
|
||
|
|
## Setup (once per clone)
|
||
|
|
|
||
|
|
make install-hooks
|
||
|
|
|
||
|
|
Installs the triage hooks and the `git cp` alias by pointing `core.hooksPath` at `.githooks/`.
|
||
|
|
Because that shadows the machine-global hook directory (`~/.config/git/hooks`, which holds the
|
||
|
|
mandatory security `pre-push`), `.githooks/pre-push` is a shim that re-execs the global hook,
|
||
|
|
and the installer verifies that delegation before it changes anything. `git` never auto-adopts
|
||
|
|
a repository's `core.hooksPath`, so this step cannot be skipped.
|
||
|
|
|
||
|
|
Note: `core.hooksPath` applies repo-wide, but `.githooks/` is a tracked directory. The hooks
|
||
|
|
(and the security shim) only run on branches that actually contain `.githooks/`. Keep it present
|
||
|
|
on `dev` and `main` so no branch loses the security `pre-push`.
|
||
|
|
|
||
|
|
## Finding what to pick
|
||
|
|
|
||
|
|
make triage-sync # git fetch upstream, then append new dev..upstream/main commits
|
||
|
|
# to the ledger as `untriaged` (PR # + subject parsed from each)
|
||
|
|
|
||
|
|
`triage-sync` is the discovery step: it records every diverged commit as `untriaged` and bumps
|
||
|
|
"Last synced" to the new `upstream/main` tip. Triage those rows (decide `deferred` / `wont-merge`
|
||
|
|
and which branch), then pick the ones you want. The underlying views if you prefer raw git:
|
||
|
|
|
||
|
|
git fetch upstream
|
||
|
|
git log --oneline --no-merges dev..upstream/main # everything diverged
|
||
|
|
git show <sha> # inspect before deciding
|
||
|
|
|
||
|
|
Cross-check candidates against the ledger first — most diverged commits already carry a
|
||
|
|
decision (already-in-dev, regression, deferred, or landed) and should not be re-examined.
|
||
|
|
|
||
|
|
## Bringing in commits: `git cp`
|
||
|
|
|
||
|
|
git cp -x <sha> # pre-check the ledger, cherry-pick -x, auto-reconcile
|
||
|
|
git cp -x <sha1> <sha2> ... # several, applied in the given order
|
||
|
|
git cp --continue # after resolving a conflict; also reconciles
|
||
|
|
git cp --force <sha> # override a SHA the ledger marks "Won't merge"
|
||
|
|
|
||
|
|
`git cp` reads `docs/upstream-sync/triage.jsonl` before touching the tree and refuses a
|
||
|
|
known-reject SHA (override with `--force`). On success it runs `make triage-reconcile`, which
|
||
|
|
moves each applied SHA to Landed in the ledger and stages `triage.jsonl` + `triage.md` for you
|
||
|
|
to commit.
|
||
|
|
|
||
|
|
Apply commits in upstream chronological order (oldest first), not the order you happen to list
|
||
|
|
them — a later commit often depends on an earlier one, and out-of-order picks conflict
|
||
|
|
needlessly:
|
||
|
|
|
||
|
|
git log --reverse --topo-order --format=%h dev..upstream/main
|
||
|
|
|
||
|
|
## The triage ledger
|
||
|
|
|
||
|
|
`docs/upstream-sync/triage.jsonl` is the source of truth: one JSON row per upstream SHA, keyed
|
||
|
|
on the SHA (stable, unlike the local SHAs cherry-pick rewrites). `docs/upstream-sync/triage.md`
|
||
|
|
is generated from it and must not be hand-edited. Dispositions are `landed`, `wont-merge`,
|
||
|
|
`deferred`, `untriaged`.
|
||
|
|
|
||
|
|
scripts/triage.py set <sha> --disposition deferred --branch slack-tooling --reason "..."
|
||
|
|
make triage-render # regenerate triage.md from the jsonl
|
||
|
|
make triage-check # CI gate: fail if triage.md is stale
|
||
|
|
|
||
|
|
A SHA marked `wont-merge` is hard-blocked by both `git cp` and the `prepare-commit-msg` hook.
|
||
|
|
Override for a one-off re-evaluation with `git cp --force`, `SH_CHERRYPICK_ALLOW_REJECT=1`, or
|
||
|
|
`git config sh.cherrypick.blockRejects false`.
|
||
|
|
|
||
|
|
## Branch layout
|
||
|
|
|
||
|
|
Never cherry-pick onto `dev` directly. Work on a themed branch off `dev` and open a PR into
|
||
|
|
`dev`; the ledger's `branch` column records where each deferred commit is meant to land
|
||
|
|
(for example `slack-tooling`, `gateway-routing`, `plan-approval`, `durable-dispatch`). Keep
|
||
|
|
each PR to one theme so conflict resolution stays within one subsystem.
|
||
|
|
|
||
|
|
## Raw `git cherry-pick`
|
||
|
|
|
||
|
|
The hooks fire on a plain `git cherry-pick -x <sha>` too: `post-commit` journals each applied
|
||
|
|
pick and `prepare-commit-msg` blocks known-rejects. Run `make triage-reconcile` once at the end
|
||
|
|
to land the picks in the ledger, then commit `triage.jsonl` + `triage.md`.
|
||
|
|
|
||
|
|
## Conflicts
|
||
|
|
|
||
|
|
# resolve the files, then:
|
||
|
|
git add <files>
|
||
|
|
git cherry-pick --continue # or: git cp --continue
|
||
|
|
git cherry-pick --abort # bail out of the whole pick
|
||
|
|
git cherry-pick --skip # drop just this commit and continue the batch
|
||
|
|
|
||
|
|
A commit that conflicts because `dev` already carries a newer version of the same code is a
|
||
|
|
regression, not a merge — skip it and record the decision as `wont-merge` in the ledger rather
|
||
|
|
than forcing it in.
|