I have a GitLab repository for my application. Following some guidelines (https://nvie.com/posts/a-successful-git-branching-model/) I created a "main" branch that mirrors the production version and a "develop" branch that mirrors the version currently under acceptance test. After finishing the acceptance test, the develop version is rolled out and will be merged into main.
All worked fine until recently we had to ship an emergency change. For this, I created a branch off main, committed the changes and merged them back to main.
Now we have the next scheduled release ready on develop, so I created a merge request from develop to main. This merge request tells me that develop is 2 commits behind main (which isttrue due to the emergency branch). So I create a merge request from main to develop. Now this one is also behind develop (which is true due to the regular functional updates in this release).
In the emergency change we changed a file that should not be changed in the developmen branch (a quickfix, that we solved otherwise in the main release).
Now I cannot merge develop into main because I have to dvance develop to the main head, but I cannot do this because I would have to commit the "main" changes (or their override) into develop which is protected.
Creating a new branch to incorporate the main changes into a merge request to develop did not work.
What is the correct way to move develop to the head of main while not being able to directly commit to develop (or main)?
CodePudding user response:
It sounds like you have a setting which forces an incoming branch to be fully up to date with main
before merging into main
. This is fine to help prevent the scenario you almost found yourself in, which is when you have a hotfix
, and you don't merge those changes back into develop
, and then the next time you deploy to production from develop
you blow away the changes in the hotfix
.
If you are using that setting, you only need it enabled for merges into main
. You don't need to have that setting enabled for merges into develop
, though there is a workaround for that if you wish to leave it on for develop
as well.
Normally, after merging a hotfix
into main
, you should immediately then merge main
into develop
.1 Since develop
is a protected branch in GitLab, this might simply mean creating a Merge Request from main
into develop
. In some cases you cannot create a MR directly from main
into develop
, and instead need to use an in-between temporary branch, for example if:
- There are conflicts when merging
main
intodevelop
. - There are not conflicts, but there is at least one change that you don't wish to be applied to the
develop
branch. - You have enabled the flag on
develop
that all incoming merges must be up to date withdevelop
.
Regardless of which of the above reasons for the exception, the solution to creating the in-between branch is the same (these commands assume your remote name is origin
):
# get the latest code
git fetch
# create a new temporary branch starting from the latest develop
git switch -c merge-main-into-develop origin/develop --no-track
# Merge in main
git merge origin/main
# resolve conflicts if needed and continue to complete the merge
# push out your branch and set it to track the new branch
git push -u
Now you can create a PR from merge-main-into-develop
into develop
.
If you happen to be in exception scenario #2 above, where you don't wish to actually bring all of the hotfix changes from main
into develop
, you have a few options:
- If you want some files but not all, you could change the merge command to be
git merge origin/main --no-commit
. This will pause the merge with the files saved, and you can modify the index however you need to before committing. You might choose this option if you have some version files that were modified onmain
that you don't wish to update ondevelop
. Consider updating the merge commit message to explain what you are changing and why. - If you don't want any of the changes from the hotfix to be brought into
develop
, perhaps because you already fixed the same thing in a different and preferred way ondevelop
, you could use the merge strategy "ours, by modifying the merge command to be:git merge origin/main -s ours
. This will bring in the commits but without any of the changes. Consider updating the merge commit message to explain why you are doing this. - A similar method to number 2 is to accept the merge as is, but then revert the merge with a commit message explaining why. This has the same effect as #2, but creates one additional commit. The advantage of this method is it's easier to predict what happened simply by glancing at the commit message titles.
Ultimately, the key idea here is you need all of the commit IDs that are on main
to be present on develop
before merging develop
back into main
.
1 The Git Flow documentation suggest merging hotfix
into main
and then also merging hotfix
into develop
. That will produce the same state but will not contain the new merge commit created on main
(which is recommended). By merging main
into develop
instead you bring that new merge commit over as well and will therefore keep develop
up to date with main
. Note this also means you'll need to merge main
into develop
right after merging develop
into main
, just to bring over that merge commit!