We have three branches:masterstagingdevWe branch per issue and each issue needs to go through testing and staging before being merged to master.We branch feature branches from master and work on that feature.When ready for testing, we merge the feature branch into dev branch and TeamCity deploys to test environment.When ready for staging, we merge the feature branch into staging branch and TeamCity deploys to staging environment.This involves a lot of merge commits on dev/staging branches, but very few on master, because the feature branches are always branched from master.It's always a merge commit merged with a feature branch, so this is a merge from a merge, from a merge, from a merge, etc... So each time TeamCity has 100+ pending changes, even though there is only 1 changed file when doing:git diff dev~1...devIs there some way to minimize these merge commits? Are we doing Git wrong?
Git and merge commits
git;branching
Your workflow seems similar to the Git Flow, except that you start feature branches from master, whereas the Git Flow recommends branching from dev.The idea is that dev closely reflects the current development state. Feature branches are supposed to be very short-lived (at most a couple of days of development). So when a feature is branched from dev and merged back into dev a day later, there will be very few conflicts. The dev branch would be used for Continuous Integration.Git Flow then suggest branching a release branch (your staging) from the dev branch with multiple new features for QA and release preparation. On release, the code is merged into master so that master only contains fully tested published versions.If we were to branch new features off master (i.e. the last published version), this would ignore all other features that have been merged into dev in the meanwhile. Although the diff between dev^ and dev might be rather clean, there would be vast differences in the history:             Am                                    B..Zm  master ----x------------------------------------x            / \                  \               / staging --x---|------------------|-------------x B..Zs          /As  |         B  C..Y  |          Z /     dev x-----|---------x--x--x--|-----------x         A      \       /  /  /   |          /featureB         x--x--x  .....   |         |                 B1 B2 B3         |         |  ...                             |         |                                   \       /featureZ                            x--x--x                                    Z1 Z2 Z3At merge B into dev (A) from featureB (A As Am B1 B2 B3), the merge is rather clean. We then add a couple of other features C through Y into dev. After that, the history of dev looks like A As Am B1 B2 B3 C1 C2 C3 ... Y1 Y2 Y3. That still looks reasonable. Finally, we have the featureZ branch with the history A As Am Z1 Z2 Z3  note that Am is the nearest common ancestor commit of dev and featureZ.The result is that at merge Z, we do not only test the effect of the commits Z1 Z2 Z3, but the effect of combining all the features B1 B2 B3 C1 C2 ... Y2 Y3 Z1 Z2 Z3.The impact of this problem is reduced by frequent releases, so that the difference between dev and master is not that pronounced. However, this only makes the problem smaller, and does not solve it. TeamCity seems to realise that it's actually testing all the changes you made since you last merged into master, although these are not obvious in the branch history (since dev only contains merge commits).I recreated the above branching example as an actual git repo, which is available as latk/Git-Branching-Madness on GitHub. You can look at the branch graph online, or clone the repo and inspect it yourself, e.g.:                          # tip: use git log with --pretty=oneline$ git log featureZ        # history of featureZ$ git log dev^            # complete history of dev before featureZ merge$ git log dev^..dev       # what commits were added during the featureZ merge$ git log master --graph  # display complete branching history