Skip to content

sync

git city sync brings a branch up to date with everything around it — the remote, its parent, and (with --all) the whole tree. It is the command you run most: after pulling new work into the trunk, after a teammate pushes to a shared feature, or any time a stack has drifted out of alignment.

git-city syncs by rebasing, not merging. A feature is rebased onto its parent so history stays linear and each branch reads as a clean diff against the one below it. This is the single most important thing to understand about the command.

Why rebase-first?

Usage: git city sync [branch] [--all] [--dry-run]
Argument / option Meaning
[branch] Branch to sync. Defaults to the current branch.
--all Sync every feature in the repo, parents before children.
--dry-run Print the exact git commands that would run; execute nothing.

What sync does

The behavior depends on the branch type.

Syncing a feature

For a feature branch, sync performs a full, ordered update:

  1. Fetch from the remote (with --prune).
  2. Bring the parent up to date, recursively — a feature can only be rebased onto a parent that is itself current.
  3. Absorb the remote: if the feature's own remote tracking branch has commits you don't, those are taken in first so nothing is lost.
  4. Rebase the feature onto its (now updated) parent.
  5. Force-push the result with --force-with-lease.

Step 5 uses --force-with-lease, never a bare --force: if the remote moved in a way git-city didn't see, the push is refused rather than clobbering someone else's work.

Merge strategy (for long-lived branches)

Rebase is ideal for short-lived branches synced often. For a long-lived branch against a busy parent, rebasing re-resolves the same conflicts on every sync (rerere helps, but only so much). For those, switch the branch to the merge strategy:

git config git-city.branch.<name>.sync-strategy merge

Now git city sync on that branch merges the parent in (git merge) instead of rebasing onto it, and pushes plainly — no force, because a merge only adds a commit, it never rewrites history. You resolve each conflict once; the resolution is a commit that sticks, so future syncs only surface genuinely new conflicts. The branch shows a merge tag in info/tree, and conflicts pause/continue/abort exactly as with rebase.

The default is rebase; set the key back (or git config --unset it) to return. This is a per-branch choice — most branches stay on rebase for linear history; flip only the heavy ones.

Syncing a trunk

A trunk (the configured trunk, plus any perennials) is never rebased onto anything — it is long-lived shared history. Syncing a trunk simply fetches and fast-forwards it to its remote (or rebases your local trunk commits onto the remote if it has diverged).

Trunks vs. features


--all: syncing the whole tree

--all syncs every feature in the repository in topological order — each parent is brought up to date before any of its children, so a child is always rebased onto an already-synced parent. Each trunk involved is updated exactly once, no matter how many features sit on top of it.

git city sync --all

This is the usual way to reconcile an entire stack (or several stacks) with the trunk in one command.


Previewing with --dry-run

Every mutating path through sync supports --dry-run, which prints the exact, ordered git commands it would run and then executes nothing:

git city sync --dry-run
  git fetch origin --prune
  git branch -f main origin/main
  git checkout add-login
  git rebase --onto main <base> add-login
  git push --force-with-lease=add-login:<sha> origin add-login

Nothing executed (--dry-run).

Look before you leap

--dry-run is the fastest way to understand what a sync will do to a particular branch — especially before a --all run across an unfamiliar tree. It is read-only and safe to run any time.


When a rebase conflicts

A rebase can stop on a conflict. When that happens, sync pauses rather than fails: the rebase is left in progress in your working tree, and the remaining steps are saved so the operation can be resumed.

git-city: sync add-login is paused.
  stopped on:  git rebase --onto main <base> add-login
  resolve the conflict and `git add`, then:
    git city continue   resume the operation
    git city abort      undo everything and return to the start
    git city info       show this and the repo status

Resolve the conflicted files, git add them, then choose:

Command Effect
git city continue Resume the paused sync from where it stopped.
git city abort Undo everything and return to the exact starting state.
git city info Re-print the paused-operation message above, then the dashboard.

Note

A paused operation is sticky: while one is in progress, most other git-city commands (including undo) refuse to run until you continue or abort. This keeps the repository in a single, well-defined state.

Resolving conflicts · Recovery commands


Errors

Dirty working tree

Sync moves commits, so it refuses to run with uncommitted changes:

git-city: working tree is dirty (commit or stash first)

Commit or stash your changes, then run sync again.

Sync also fails cleanly if a branch has no recorded parent and is not a trunk — git-city has nothing to rebase it onto. Use new, reparent, or insert to give a branch a place in the tree.

All errors print as a single git-city: <message> line on stderr with exit code 1 — never a raw traceback.


After sync

Once a feature is synced and reviewed, fold it into its parent with land: land fast-forwards the parent to the feature's tip, re-homes any children, pushes, and keeps the branch (tagged landed; remove it later with prune, or land with --delete). land refuses if the feature is behind its parent — which is exactly the situation sync resolves, so the two commands pair naturally: sync, then land.

land