Re-anchor after an edit
When to use this
Under an agent session, a pure line-shift (the span still describes the same content, just at a new range) is healed automatically — the touch hook re-anchors it the moment the edit lands, and no manual step or extra commit is needed. This guide is for what that hook can't do on its own: content itself changed in a way that needs a human or agent judgment call about whether the coupling still holds, or you're re-anchoring outside a hooked session (CI, a human-authored commit, drift --fix run by hand).
Use this when you've deliberately changed the code a span anchors — moved a function, changed its size, or otherwise made its old line range wrong — and git span drift now reports it as drifted. This guide covers the manual re-anchor step. If you haven't triaged the drift yet, start with Reconcile drifted spans.
Find the new range
Open the file and locate the code the span should now point at. Before writing an #Lstart-Lend address, check the file's current line count:
wc -l path/to/file.tsAnchor line numbers are 1-indexed and inclusive, and the end line can't exceed the file's line count — git span add rejects it:
error: invalid anchor: end=200 exceeds file line count (7)A reversed range (L6-L4, end before start) doesn't get a clear "end before start" error. It fails generic anchor parsing instead, with a message that misleadingly claims the address is missing its L prefix. If you see that error on an address that looks right, check whether start and end are swapped.
If the whole file is the right unit to anchor (not a specific range), use the bare path with no #L suffix — that's a whole-file anchor.
Same range, new content
If the code changed in place — the anchor's line range is still right, only the content differs — re-add the same address. git span add recognizes the existing anchor and re-hashes it against the current content:
git span add checkout-flow web/checkout.tsx#L4-L6Added 0 anchors and resolved 1 in place to span `checkout-flow`.
- resolved in-place: `checkout-flow` `web/checkout.tsx#L4-L6` (hash changed)"Added 0 anchors" is not a failure — the in-place resolution is the point. The next git span drift run reports the anchor clean. This is also how you confirm an intentional content change that drift flagged: re-adding the anchor declares "yes, the new content is what the span should track."
Before re-adding, check the span's other anchors still agree with the new content — the re-hash records the current bytes as the baseline with no semantic check. Conform a side only when confirmed authority or a satisfied gate decides it; otherwise surface the ambiguity instead of re-anchoring over disagreement. Without a confirmed contrary authority, a doc that lags deliberate committed code follows the code.
Moved range: swap the anchor identity atomically
If the code moved to a different range or path, swap the drifted address in one command:
git span replace checkout-flow web/checkout.tsx#L4-L6 web/checkout.tsx#L6-L8replace retires exactly the old identity and installs the new one in a single locked transaction — either both happen or nothing changes, so there is never an intermediate state with both anchors or neither. The new address passes the same validation as add (including the line-count check above). The swap is refused — leaving the declaration untouched — if the span doesn't track the old identity exactly, if the new identity is already tracked, or if the two addresses are the same identity (an in-place hash refresh is add's job).
add rejects an anchor that provably supersedes an existing same-path anchor — a whole-file anchor versus a range, in either direction — naming the conflict and printing the exact git span remove command to run. Disjoint same-file ranges remain valid. Remove the exact old address first, then retry the add.
Check the result:
git span show checkout-flowConfirm the span now lists the new range and no longer lists the old one.
Inherit the why only while it remains true
Re-anchoring doesn't touch the why. Inherit it only while the relationship and lifecycle state remain true; otherwise revise or retire it:
git span why checkout-flow "The browser initiates the charge request that the server validates; the server contract is authoritative for accepted fields."When a satisfied gate authorizes a behavior change, complete it, revise or retire the why, retire every superseded anchor, and run the required code checks before requiring scoped zero drift.
Commit
git add .span && git commitBefore committing, run scoped git span drift checkout-flow and require zero drift. add refreshes only the exact path/range specified; it does not retire a different superseded anchor — replace is the one-command identity swap — and an anchor that provably supersedes an existing same-path anchor (whole-file vs range, either direction) is rejected with the exact git span remove command printed.
See also
- Reconcile drifted spans for the full triage workflow, including when
drift --fixcan do this automatically. - Concepts for the definitions of span, anchor, and why.