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.