gitgitlab

Main branch of the mirror (X) repository diverged from mirrored repository(Y) and Gitlab fails to synchronize the mirror with the lastes updates


My problem:

In GitLab, I have one repository (called X) whose main branch mirrors the "main" branch of a public repository (called Y). So, GitLab does periodic synchronizations to the main branch of X (mirror) with the latest changes merged on the main branch of Y (mirrored), until last night when I accidentally merged some changes onto the main branch of X. Now, in GitLab, next to the main branch of X, I have a message saying: "main default> protected diverged from upstream"

If I hover over diverged from upstream I see the following message: "The branch could not be updated automatically because it has diverged from its upstream counterpart. To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above.", although, this message seems very ambiguous to me, especially the "delete it here and choose 'Update Now' above .".

I don't think I can delete the main branch, and right now I don't think I want to do it.

Because of this, the periodic/forced synchronization with the main branch of Y fails now.

Even after reverting the commit that I accidentally merged on the main branch of X, it didn't solve the problem, as I'm still unable to synchronize with Y.

My question:

Is there any way to get to the state where I can do periodic synchronization again from the main branch of Y and have the main branch of X in sync again with Y.

I tried a git reset --hard origin/main and had the following message:

git reset --hard origin/main

HEAD is now at 4e4b83e Merge branch 'revert-d3a10f32' into 'main'.

Obviously, what Gitlab is suggesting, is probably impossible as the main branch of X is the default branch which I don't think can be removed.


Solution

  • If the synchronization between the two remote repositories Y and X fails because X has diverged from Y, when you perform on your local repository a git reset --hard origin/main, you're not resetting the local branch main to the commit prior to the divergence, you're just resetting your local main branch to X's main branch. Both your local and remote repository are still diverging from Y.

    If you want to resume the synchronization, X's main branch shouldn't contain any additional changes than Y's main branch, as GitLab simply performs a fast-forward between the two. You need to bring X to a point before the divergence. To do that, find the last common ancestor between X and Y's main branches. So, add Y as a second remote, and fetch its main branch. At that point, perform a git merge-base between main and y/main and reset your local main branch to the merge-base commit. Finally, force push to the remote repository X, so that X's main is back to a point contained by Y's main's history.

    # add Y as the second remote
    git remote add origin2 Y
    
    # fetch main from Y
    git fetch origin2 main
    
    # find the most recent common ancestor between your local main (which corresponds to X) and Y's main
    git merge-base main origin2/main
    
    # copy the SHA1 returned from git merge-base
    
    # reset to the most recent common ancestor
    git reset --hard <SHA>
    
    # force-push to overwrite X's `main` with your local
    git push --force origin main