Summary
internal/sync/sync.go syncTarget phase 4 calls git push -u origin main unconditionally. Phase 2 (fetch+merge) tries origin/main first and falls back to origin/master, but phase 4 has no such fallback. The result on remotes whose default branch is master — notably GitHub wikis, which still use master as the canonical branch — is that the push lands on a brand-new main branch instead of updating the user-facing wiki content.
Reproduction
- Configure sync to a GitHub wiki remote (
https://github.com/<user>/<repo>.wiki.git) with direction: push or bidirectional.
- Make a local edit.
- Trigger a sync tick.
- Push succeeds but
gh api repos/<user>/<repo>.wiki shows two branches: original master (unchanged) and new main (with the local edit).
- The wiki UI on github.com keeps showing the unchanged
master. The user thinks the push worked because the sync target reports no error.
Hit during
Image-support feature demo. Local clone state:
$ git ls-remote https://github.com/aniongithub/mind-map.wiki.git
e82a3fc... HEAD
4d2aa10... refs/heads/main ← our local commit, freshly created branch
e82a3fc... refs/heads/master ← wiki UI shows this, unchanged
Worked around by pushing manually with git push origin main:master and then git push origin --delete main.
Proposed fix
Phase 2 already does branch detection — extract that into a small helper that returns the actual upstream branch name (whichever of main/master exists on origin) and have phase 4 push to the same one. Code sketch:
func detectRemoteBranch(ctx context.Context, dir string) (string, error) {
for _, b := range []string{"main", "master"} {
if err := gitCmd(ctx, dir, "rev-parse", "--verify", "origin/"+b); err == nil {
return b, nil
}
}
return "main", nil // fresh remote with no branches yet; "main" is a reasonable default
}
Then in phase 4:
branch, _ := detectRemoteBranch(ctx, t.cloneDir)
if err := gitCmd(ctx, t.cloneDir, "push", "-u", "origin", branch); err != nil { ... }
Phase 2 should reuse the same helper instead of inlining the fallback loop.
Why this is a bug, not a feature request
- The user explicitly configured push or bidirectional sync. The expectation is that the remote's user-facing branch updates, not that some new branch appears and is silently ignored by the wiki UI.
- No error is surfaced. Status reports success, the local wiki appears in sync, but the public wiki is unchanged. This is the worst kind of "silent partial failure."
- Affects every GitHub wiki user (likely the majority of mind-map sync targets, since
<repo>.wiki.git is the dominant deployment mode).
Related code
internal/sync/sync.go syncTarget — phase 2 (~line 356) and phase 4 (~line 386) per the current branch tip
- Tests are in
internal/sync/sync_test.go — TestManagerSyncWithLocalRemote uses --initial-branch=main for the bare remote, which is why this didn't surface in unit tests. A test using --initial-branch=master (or both, parameterized) would have caught it.
Summary
internal/sync/sync.gosyncTargetphase 4 callsgit push -u origin mainunconditionally. Phase 2 (fetch+merge) triesorigin/mainfirst and falls back toorigin/master, but phase 4 has no such fallback. The result on remotes whose default branch ismaster— notably GitHub wikis, which still usemasteras the canonical branch — is that the push lands on a brand-newmainbranch instead of updating the user-facing wiki content.Reproduction
https://github.com/<user>/<repo>.wiki.git) withdirection: pushorbidirectional.gh api repos/<user>/<repo>.wikishows two branches: originalmaster(unchanged) and newmain(with the local edit).master. The user thinks the push worked because the sync target reports no error.Hit during
Image-support feature demo. Local clone state:
Worked around by pushing manually with
git push origin main:masterand thengit push origin --delete main.Proposed fix
Phase 2 already does branch detection — extract that into a small helper that returns the actual upstream branch name (whichever of
main/masterexists on origin) and have phase 4 push to the same one. Code sketch:Then in phase 4:
Phase 2 should reuse the same helper instead of inlining the fallback loop.
Why this is a bug, not a feature request
<repo>.wiki.gitis the dominant deployment mode).Related code
internal/sync/sync.gosyncTarget— phase 2 (~line 356) and phase 4 (~line 386) per the current branch tipinternal/sync/sync_test.go—TestManagerSyncWithLocalRemoteuses--initial-branch=mainfor the bare remote, which is why this didn't surface in unit tests. A test using--initial-branch=master(or both, parameterized) would have caught it.