We are currently using Git flow as a branching strategy, and we are squashing our feature branches into develop. We are also squashing our release branches into main.
The AzDO branches page show differences in commits between develop -> main, which I expect, but it also shows major differences in the files, which when doubled checked in git CLI are erroneous.
Does anyone know how AzDO compares branches? And more importantly can it be configured?
I was expecting to see commit differences but no file changes.
I believe the Azure DevOps (AzDO) compare branches screen uses the same diff as the Pull Request view, which is diffing the merge-base of the two branches with the source branch. So for example, if you are comparing
developtomainon the branches screen, the diff would be the same view you see if you create a PR ofdevelopintomain(which you probably wouldn't do in Git Flow), and would be equivalent to the following command (using Git Bash):The equivalent shorthand 3-dot diff syntax would be:
Presumably the command line diff syntax you're using (and preferring) is 2 dots (which is equivalent to zero dots):
AFAIK it isn't possible to change the diff AzDO uses on the branches page, so you'll have to use command line or your favorite UI to see that diff.
I believe at this point your specific questions have been answered, but this answer wouldn't be complete without discussing the reason why you like the no dots diff, and the reason AzDO uses the 3 dots diff.
Motivation behind the 3-dot syntax
It turns out that most people, most of the time, prefer the 3 dots diff in a Pull Request. Arguably, the branch compare screen is intended to be used in preparation for a merge (or PR) and so it makes sense to show the same diff on that screen too.
This may not be the best view for your described scenario though, because your default view is going to be scary; it will look like you're about to change many files that you know aren't actually changing. In the PR view there is an option to "View merge commit" and that will show you what will actually change, if you complete the PR at the moment that merge commit was generated. As soon as the source or target branch changes, the merge commit will need to be re-calculated, and there is an option for that as well if needed.1 The changing of the target branch is the reason most people prefer the 3-dot syntax. Here's an example:
Suppose,
featurefrom the latestdevelop. At this momentfeatureanddevelopare identical, which means they are pointing to the same commit.develop. You push your branch, and create a PR in AzDO to mergefeatureintodevelop.developwith the squash merge strategy, and nowdevelophas 5 new commits on it that your branch doesn't know about.The PR uses the 3 dot syntax diff, which shows you only what changed on
featuresince you branched off ofdevelop. This should match the changes you made and makes it easy to do a code review. If the PR used the regular diff syntax, you would see a straight diff betweenfeatureanddevelopwhich would include all of the changes in the other 5 commits that had nothing to do with the changes you made. This would be confusing to see and would be difficult to code review.Now, I'm guessing you agree with the previous paragraph for the scenario of merging a
featurebranch intodevelop, and on the branches "compare" page you would see the same thing when comparingfeaturetodevelop. But why then is the compare ofdevelop(orrelease) tomainshowing many changes that are already onmain? (And the same should be true when you create a PR ofreleaseintomain.)The reason you're having this issue is due to a slight flaw in your workflow:
As a rule of thumb, you should never rewrite a shared branch.
In Git Flow, the shared branches are
develop,main,release, andhotfix. So this means any time the source branch of a Pull Request is one of those branches, you should not rewrite the branch. In AzDO, there are 4 merge strategies to choose from when completing a PR:All but strategy #1 might rewrite the source branch, so that means when doing a PR where the source branch is one of the special shared branches, the only strategy you should complete the PR with is #1 (Merge). So, it's fine to use the squash strategy when completing feature branches into
develop, and you can also use squash when completing bug fix branches intoreleaseorhotfix, but when PR'ing any of those 4 shared branches into another branch, you should not squash, or rebase. Because you have been squashingreleaseintomainfor a while, you've been rewriting all of those commits every time which means many of the commits ondeveloparen't ever landing onmain. Therefore the 3 dot syntax of "What have I changed ondevelopsince I branched off ofmain?" has lots of commits in it- and consequently many more changes showing up that are already there. It probably gets worse every time you merge areleasebranch intomain.The Fix
The first thing you should do is merge
mainintodevelopwith a regular merge. If you use a PR then you should select merge strategy #1, because the source branch,main, is a shared branch.From then on, follow the rule of thumb and this problem should mostly2 go away.
Side Note
Git Flow recommends using
--no-fffor every merge, but that is actually only necessary for PRs that are merging in more than 1 commit. If you don't care about the individual commits, squashing is compatible with Git Flow as long as you never use it for merging any of the shared branches. In one of my Git Flow projects in Azure DevOps, we setup a branch policy ondevelop,release, andhotfixto only allow "Semi-Linear Merge" (which does a rebase and then forces a merge commit with--no-ff). If you prefer Squash you could do the same on those branches but lock it to Squash. However, anytime we do a merge where the source branch is one of the shared branches, e.g.releaseintodevelop, then we use the Override functionality so that certain people can complete those merges with the regular "Merge" strategy. I haven't figured out a clean way to enforce that rule for certain shared branches, though it would be nice if it were possible.1 In AzDO Pull Requests, the merge commit is automatically re-calculated anytime the source branch changes, but not when the target branch changes. If you wish to recalculate it after the target branch changes you can. At the moment you complete the PR it will also recalculate it if needed. Note this means it's possible to not know there are merge conflicts until the moment you attempt to complete the PR, if the target branch has changed and caused new merge conflicts since the last time the merge commit was generated.
2 It's still possible to have the same problem under normal circumstances without violating the rule of thumb about never rewriting a shared branch. For example, suppose someone completed a PR into
developand then soon after realized that the change really ought to have gone into thereleasebranch instead. So the change is cherry-picked over to a feature branch coming off ofreleaseand then PR'd intorelease. Now there are 2 different commits with the identical changes in them, and whenreleasegets merged back intodevelop, that PR will show those changes even though they are already indevelop, simply because they are (purposefully) in two different commits. This is one of the reasons for another rule of thumb in Git: "Avoid cherry-picking if it's possible to achieve the same thing with a merge instead." If you knew in advance that you needed the change on bothdevelopandrelease, then you would merge that intorelease, and then mergereleasedown todevelopsince you can do that anytime. Or, if possible, the change could branch off of the merge-base ofdevelopandrelease(or even the original commit where the bug was introduced!), and then the new commit could be merged into bothdevelopandrelease.