How to avoid hard resetting a fork, every time?
My team works on a forked gitlab repo (origin). When the team members are done pushing their commits to origin, we issue a merge request to the upstream repo.
The merge request gets approved by another team and we have no governance over the upstream, whatsoever. Also, we never push directly to the upstream.
While the merge request waits for approval, my team keeps on pushing to origin.
The problem is, every time we want to issue a new merge request (and a previous one has been approved) we find ourselves unable to rebase to the upstream. The new merge request contains both new commits and all commits already merged in the upstream. We end up issuing the new merge request and as soon as it is approved, we then hard resetting to the upstream and force push to origin:
git fetch upstream git reset --hard upstream/main git push --force
Obviously, this is wrong. When the merge request has been approved and there are new commits to origin, why can’t we rebase, cleanly? Instead, all commits (included in the approved merge request) appear as conflicts.
How can we avoid hard resetting the origin, every time?
It sounds like the maintainers of the upstream repository are rewriting the history as they merge it – most likely, they’re using "squash merges", which throw away all your history and create a single commit combining all your changes.
The ideal would be to point out to them how much extra work this is causing you, and ask them to use a true merge (merge commit) so that git can do its job of tracking the relationship between the branches.
Assuming you can’t do that, you will need to reset / rebase changes onto their new history at some point. However, you could make this easier by avoiding long-running branches:
- Each feature you develop should be its own branch.
- Your merge requests should be from one of these branches, not your fork’s "main". That way, you don’t need to merge to your local "main", and it won’t become out of sync with the upstream one.
- When possible, start new feature branches directly from the latest upstream "main".
- If you need to base one of your features on another, you will need to rebase it once the upstream has accepted the first feature. Specifically, you need the three-argument version of the rebase command, which I remember as "git rebase old_base old_tip –onto new_base" ("rebase the commits from old_base up to old_tip onto new_base"), e.g.
git rebase feature-42 feature-43 --onto upstream/main
In short, completely ignore the "main" branch on your fork (origin) and always use the "main" branch on the central copy (upstream). Don’t create any branches from origin/main, don’t commit to that branch, and don’t merge anything there.
Answered By – IMSoP