Files
command-center/agent/managed-skills/gitflow-back-merge-plumbing/SKILL.md
T

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

  1. git fetch origin and verify with git ls-remote --heads.
  2. 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.
  3. 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 from ls-files -u in some other worktree.
  4. 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).
  5. 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).
  6. 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.
  7. Verify ALL of: git merge-base --is-ancestor origin/main origin/develop; grep a distinctive merged value in origin/develop:<file> (content, not just ancestry); git diff --stat origin/main origin/develop matches expectations.

Traps

  • merge-tree writes 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/json AND {"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.