I work with a feature branch model where the branches get merged into master when they are ready. Before a larger test (specific to my field of work, involving a lot of heavy hardware), several feature branches (individually tested using simulations) are merged into one "test" branch.

Before the actual test, the "test" branch is again tested using simulations. If, during this test, issues arise due to the way the individual branches behave together (or other bugs arise that weren't seen before), I'd like to be able to make a fix on the individual feature branch but keeping the "test" branch merged.

At the moment, I usually delete the test branch (the merge commit), make the fixes on the respective feature branch and then merge all the relevant branches into the "test" branch again. This is a bit tedious. Of course, I could make some small scripts etc. But in my situation, I have multiple repositories with "test" branches all with different feature branches merged together and writing scripts for all those ... I'd rather look for a better solution.

My question: Is there a way to have some sort of "dynamic" merge, so that, when I add a commit in a merged feature branch, the "test" branch merge is updated with that commit just as if it had been merged with that commit already on the feature branch.

I hope the idea is clear. If not, please let me know so that I can clarify.

  • 2
    Would it be an option to make the fix on the feature branch and then merge the bugfix into the test branch without deleting the previous merge commit? – Bart van Ingen Schenau Nov 2 '18 at 20:20
  • @BartvanIngenSchenau Yes, that would be possible, thanks. But for the sake of keeping the history slightly cleaner, I'd prefer not to. However, between your suggestion and me repeatedly deleting and recreating the merge commit, I probably would use your suggestion. I actually don't think the feature I am envisioning exists, but maybe someone else with a similar workflow has solved it differently. – Bert Nov 2 '18 at 21:49
  • You might try using git reparent or similar solution to change commit parents after merging the fix. However, I strongly advice against it: messing with git history is risky, and the benefit almost purely esthetical. – Frax Nov 3 '18 at 12:31
  • Btw, is git co test && git reset --hard master && git merge b1 b2 b3 b4 that bad? And if the list of feature branches is that long, perhaps list them in .git/myfeaturebranches and then make it git merge $(cat .git/myfeaturebranches) or something. – Frax Nov 3 '18 at 12:35
  • But really, just do a second merge and keep it. – Frax Nov 3 '18 at 12:38

Git doesn't have particularly good support for this. The conceptual problem is that each Git commit represents a project state, not a diff. Merging two branches means combining the differences between the two branches' project states. Typically this is easy because Git applies non-conflicting changes from either branch. But when you add a commit to a feature branch and then merge it again, that will be roughly as difficult as the first merge and you will potentially have to solve many of the same conflicts again. Although git-rerere can be locally enabled to reuse a recorded merge conflict resolution from a previous merge:

Another application of rerere is where you merge a bunch of evolving topic branches together into a testable head occasionally, as the Git project itself often does. If the tests fail, you can rewind the merges and re-do them without the topic branch that made the tests fail without having to re-resolve the conflicts again.

To enable rerere functionality, you simply have to run this config setting:

$ git config --global rerere.enabled true

Git Book / Pro Git 2nd ed. by Scott Chacon, Ben Straub.

Consider why you need the feature branches and what the test branch represents. If the test branch will move on to become something like a release candidate, there is limited value in committing additional changes to the feature branches (and then having to merge again). Instead, consider committing the change as a hot fix directly on the test branch. If the test branch is not the basis for a release, note that you are testing a different system than you are releasing, especially as merge conflicts might be resolved differently.

You can also cherry-pick or rebase the fix from the feature branch to the test branch, or vice versa. This duplicates the changes in the commit on top of another history. There might be conflicts, but typically more limited than a full merge.

Neither merging nor rebasing can auto-update a merge commit. It is in principle possible to amend the merge commit or to squash two merge commits, but this is comparatively tricky to do. The easiest approach would be to first reach and commit the project state that you want to have after the merge, then record a new history that produces this state: reset the test branch to before that merge, start an octopus merge of all branches but --no-commit the merge, then use git-checkout to restore the working tree tho the project state that you want, and commit the result as the merge.

The best way to avoid merge conflicts in Git is to avoid long-running branches. I understand this is not always possible, but integrating features early (and possibly protecting them with feature toggles) will cause any conflicts to be raised and solved early, and only once. Similarly, an architecture where you can add new features without modifying lots of existing code will avoid conflicts. In short: shifting complexity from the branching model to the code itself.

  • I think your paragraph on "what does the test branch" represent is quite important. I did some more reading on branching models and apparently, what I am doing is similar to a part of the gitworkflow (git.git), the "proposed updates" (pu) branch. But that branch is never used directly but just as a branch to test the interplay of the branches. Anyway, I'll accept your answer, because I think it makes sense and what I want doesn't exist (and might not make a lot of sense for most people). – Bert Nov 5 '18 at 7:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.