Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep linear history in two branches preprod and production

I have two branches in github preprod and production, both are protected and enforce linear history that means all the changes to that branches needs to be done by "rebase/merge" or "squash/merge".

Every new feature added to the preprod branch is made by feature braches.

a          <-- production
 \
  b        <-- preprod
   \
    c -- d <-- featureA

When I merge featureA to preprod with squash/merge, 'c' and 'd' create a new commit in preprod.

a           <-- production
 \
  b -- e    <-- preprod
   \    ^
    \    \
     c -- d <-- featureA
       

After a couple of new features I merge preprod to production with the same method squash/merge. This end up looking like this.

a ------------ h     <-- production
 \              ^
  \              \
   b -- e -- f -- g  <-- preprod

After a couple of merges from preprod to production the branches had the same code but the commits history is different because the squash/merge create commits in production branch that are not in preprod, this is creating too many conflicts each time I do a new pull request, because is trying to merge all the changes from commits 'b','e','f','g','i' and 'j'. It looks like this.

a ------------ h ------- k     <-- production
 \              ^         ^
  \              \         \
   b -- e -- f -- g -- i -- j  <-- preprod

Update: as @matt mention correctly, this is the real graph

a ------------ h ------- k     <-- production
 \                       
  \                      
   b -- e -- f -- g -- i -- j  <-- preprod

This is getting worst over time, I need a way to sync preprod branch with production so in new merges the pull request only look for the new commits no for the onces already merged.

At this stage a can't do rebase/merge becase of the conflicts so I don't know what to do. Last time, to merge changes from preprod to production I was block by github becuase of the conflicts, I solved it following this guide

# in case branchA is not our current branch
git checkout branchA

# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB    

# make temporary branch to merged commit
git branch branchTEMP         

# get contents of working tree and index to the one of branchB
git reset --hard branchB

# reset to our merged commit but 
# keep contents of working tree and index
git reset --soft branchTEMP

# change the contents of the merged commit
# with the contents of branchB
git commit --amend

# get rid off our temporary branch
git branch -D branchTEMP

# verify that the merge commit contains only contents of branchB
git diff HEAD branchB

That solved the conflicts becase I can just use the version that is on preprod and ignore the conflicts.

I want to have this long live branches in sync and protected becase I have some github actions running the build and the tests and I think both branches need to be protected and have a linear history becase both are automatically deploy to its corresponding server after build and test passed. keeping linear history allow me to easily see the changes bewteen deploys, but merging from preprod to production is becoming a bottle neck.

Any idea how to solve this?

like image 758
Simon Puente Avatar asked Nov 27 '25 07:11

Simon Puente


1 Answers

this is creating too many conflicts each time I do a new pull request, because is trying to merge all the changes

Yup, well, long-lived branches and squash merges are opposites, for this very reason. You've picked a bad way to go. There is a reason why real merges exist: they move the merge-base for future merges. You are not taking advantage of that fact.

Your diagrams are wrong and may be misleading you. You have, for example:

a ------------ h ------- k     <-- production
 \              ^         ^
  \              \         \
   b -- e -- f -- g -- i -- j  <-- preprod

No. The line between g and h, the line between j and k, is phoney. The reality is:

a ------------ h ------- k     <-- production
 \          
  \           
   b -- e -- f -- g -- i -- j  <-- preprod

There is absolutely no relationship, topological, historical, or otherwise, between g and h, or between j and k. On the contrary, h and k are created mysteriously out of the blue. But they are still formed using merge logic. The merge base used for that merge logic never moves: it will always be a. And so, as life goes on, if preprod stays alive and you try to do this again and again, it will become harder and harder to do, as reflected in the ever growing number of conflicts.

To sum up: what you're doing is not the purpose for which rebase/squash "merges" are designed. These are not merges. In my opinion you should give up your goal of "linear history" — it isn't history at all, that's the whole problem. You should embrace true merges.

like image 157
matt Avatar answered Nov 28 '25 22:11

matt