Skip to content

Bug: Target branch divergence/No merge-base error loop after Git history rewrite #14415

Description

@shanoor

Version

0.20.3

Operating System

Windows

Distribution Method

msi (Windows)

Describe the issue

When rewriting git history upstream (e.g. changing commit author name/emails using git filter-branch or git filter-repo) and pushing the rewritten history, the local GitButler client gets stuck in a perpetual "Target branch divergence" or "No merge-base found" state.

Even if the user deletes .git/gitbutler, clears local %APPDATA%/gitbutler caches, and runs but teardown / force-resets all local branches, GitButler continues to re-create the gitbutler/workspace branch pointing to the old (pre-rewrite) commit SHAs.

Root Cause Analysis

The persistent loop occurs because GitButler caches the target branch's base commit SHA in the local .git/config file under the key:
gitbutler.project.targetcommitid

When the user runs but setup or restarts the GitButler client:

  1. GitButler reads gitbutler.project.targetcommitid from .git/config (which still points to the old, pre-rewrite commit SHA).
  2. It recreates gitbutler/workspace starting from this old commit.
  3. Because the remote origin/master has been rewritten, the old commit and the new remote master branch share no common history (there is no merge-base).
  4. GitButler reports "Target branch divergence" and crashes with:
    API error: (get_initial_branch_integration) - No merge-base found between 'refs/heads/gitbutler/workspace' and its tracking branch 'refs/remotes/origin/master'

Workaround / Manual Resolution

To recover, the user must manually purge the GitButler keys from the local Git configuration before setting up again:

# Exits GitButler mode
but teardown

# Manually remove the targetcommitid config caching the old SHA
git config --local --remove-section gitbutler.project

# Re-align local branches and clean up
git checkout master
git reset --hard origin/master
git branch -D gitbutler/workspace
git branch -D gitbutler/target
Remove-Item -Recurse -Force .git/gitbutler

# Re-initialize
but setup

Suggested Fixes

  1. Dynamic Target Resolution: GitButler should ideally check if the cached targetcommitid is still present or reachable in the target branch's current history. If it is not (indicating a history rewrite), it should prompt the user to re-evaluate the target base rather than erroring out.
  2. Setup Clean-Up: When running but setup on an existing directory, it should detect if the current base branch HEAD is different from the cached targetcommitid in .git/config and offer to update it.

How to reproduce (Optional)

  1. Initialize a repository with GitButler.
  2. Rewrite the repository history upstream (e.g., using git filter-branch to change commit author details).
  3. Force-push the rewritten history to origin/master.
  4. Attempt to update the local workspace or re-align branches in GitButler.
  5. Note the "Target branch divergence" error.
  6. Try resolving it by deleting .git/gitbutler, local app data caches, and recreating the tracking branches.
  7. Observe that GitButler keeps regenerating the workspace branch using the old target commit SHA.

Expected behavior (Optional)

No response

Relevant log output (Optional)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions