3.0 KiB
3.0 KiB
name, description
| name | description |
|---|---|
| gitflow-back-merge-plumbing | (HISTORICAL for dank/command-center — switched to trunk-based 2026-10-18, no develop branch.) Back-merge main into develop with pure git plumbing when branch checkout is policy-blocked; avoids the polluted-base evil-merge trap. |
Git-flow back-merge via plumbing (checkout blocked)
Applicability
The command-center repo retired develop on 2026-10-18 (trunk-based; see its AGENTS.md § Trunk-based SDLC). Use this only in repos still running git-flow where a main -> develop back-merge must land and branch checkout is forbidden. Never merge while HEAD is a session branch — the merge silently lands on it.
Procedure
git fetch originand verify withgit ls-remote --heads.- Find the CLEAN fork point:
mb=$(git merge-base origin/develop origin/main). NEVER build the merge commit with a develop-side that already contains main (e.g. a previous broken merge): merge-base then equals main, main-side looks "unchanged", and stale develop content wins everywhere — a clean rc=0 evil merge. Sanity-trigger: if a merge you expect to conflict resolves rc=0, suspect the base. - Real merge, no worktree:
out=$(git merge-tree --write-tree <clean-dev-tip> origin/main); rc=$?; tree=$(echo "$out"|head -1). rc=1 = conflicts; list them from the "Conflicted file info" section (lines starting with a 6-digit mode), NOT fromls-files -uin some other worktree. - Resolve in index only:
export GIT_INDEX_FILE=/tmp/idx.$$; git read-tree $tree; git update-index --add --cacheinfo 100644,$(git rev-parse origin/main:<path>),<path>per conflicted path (pick a side deliberately — say which in the message). final=$(git write-tree); prove no markers:git grep -l '^<<<<<<<' "$final"must be empty (run it correctly — an empty count from a malformed invocation hides markers).commit=$(git commit-tree "$final" -p <clean-dev-tip> -p origin/main -m "...");git push --force-with-lease=develop:<current-dev-tip> origin "$commit:develop"(lease prevents clobbering concurrent pushes; document superseded commits). A back-merge onto an untouched develop is additive — plain push, no lease needed.- Verify ALL of:
git merge-base --is-ancestor origin/main origin/develop; grep a distinctive merged value inorigin/develop:<file>(content, not just ancestry);git diff --stat origin/main origin/developmatches expectations.
Traps
merge-treewrites conflict markers INTO the tree for conflicted paths — always overwrite every conflicted path before commit-tree.- A wrong tree pushed as a merge commit makes every later merge against it resolve "cleanly" to stale content; fix by rebuilding from the clean fork point and force-with-lease, citing the broken commits in the message.
- Gitea PR merge API needs
Content-Type: application/jsonAND{"Do":"merge"}in the BODY (query param alone 422s); a 405 "Please try again later" right after the base branch moved is transient mergeability recomputation — wait a few seconds and retry.