5 ms·
Personally, I simply don't want to see any merge-commits, ever. Merges are hard to follow and may include conflict resolutions which are hard to show (if they s
by the_gipsy 3y ago
Personally, I simply don't want to see any merge-commits, ever. Merges are hard to follow and may include conflict resolutions which are hard to show (if they show up at all).
Sure, "merging" is an amazing feature. But I am not working on projects with an organizational complexity like the Linux kernel. Short-lived & rebased branches so that code gets integrated into main fast. Conflict resolution is never postponed nor shared. Versioning/release/deploy/rollback is dealt with mostly outside of git, or with tags-on-main at most.
- yakubin 3y agoMerge commits also break regression finding, since if you checkout a commit that was part of a merge, you land in a tree state reflecting what tree at this commit looked like before the merge, which is a state the master branch has never been in. It often breaks things which work both before and after the merge commit. So you can never find with certainty the regression point at commit level, other than locally linearising this merge into a series of cherry picks. It’s just awful.
- dbt00 3y ago--first-parent, and both with git bisect and many other things, is your friend here.
- yakubin 3y agoThat doesn’t fix the issue I described. It leads to a situation where you can say that a merge introduced a regression, but you don’t know which of the merged commits did, because it skips over them all. So it’s not commit-level.
- leghifla 3y agoOn the other hand, rebasing can create its own problems re: regression finding If you rebase more than one commit, you can also have an intermediate commit which does not run fine, or even compile. This can happen silently, without conflict resolution while you rebase. Think a function call in trunk needs one additional parameter. So you have a commit message saying "Protocol X tested successfully with Y", which was true when the code done and tested. After the rebase, it might not run anymore because of changes done in the trunk. You will probably notice it and correct it in a later commit, but good luck in 3 month when someone points a bug at protocol X and you want to re-run the test in this commit...
- yakubin 3y agoThat’s why at work we have a “commit queue” that tests that every commit builds as it comes in in the order it’s merged (or more accurately: cherry-picked). Don’t leave those things to manual checks and human vigilance. They’re too fallible.
- the_gipsy 3y agoI think this can be mostly worked-around by requiring branches (PRs) to be rebased and tested/CI-passed before merging. If PRs contain multiple commits, either squash them (on merge or before), or use some kind of queued / stacked PR system.
- rewmie 3y ago> Versioning/release/deploy/rollback is dealt with mostly outside of git, or with tags-on-main at most. This is simply outright wrong. Releases are not a tagged versions of a development branch. There is stuff that belongs in releases but should not be present ever in develop branches at all, and vice-versa. Once you need specific changes going into a release, you need branches. Also, you should not block development work on the development branch just because you need to push a release. Also, if you find a bug in a release candidate, you fix that bug alone. You do not add other changes just because someone committed them to the development branch. Cutting a release means picking up an unstable version and work your way up to make it stable. This means freezing the introduction of additional random features, and commit bugfixes only. Tagging does not allow that.
- the_gipsy 3y ago> Once you need specific changes going into a release, you need branches. I don't have this need. Then I don't need to deal with the sheer insanity of loosely spreading all those different git refs you mention over everything including the future. Changes get integrated fast into main, because nothing is blocked, frozen, or left for someone else in the future. This also makes commits/PRs/changes small. Feature flags are used to ease this even more. In the face of absolute disaster it is possible to simply revert/rollback a release/deploy. However in practice I don't really need to do this, almost never. Some hotfix here and there maybe, but it's still all much faster than the sheer insanity of git-flow overcomplications. Often a hotfix is the only solution, a revert/rollback fixes nothing when the problem is outside of git (DBs, client storage...). In the end, you have to evaluate all the time you sink into this model, and how much risk you actually mitigate. Wherever I've seen git-flow, the overhead was huge and ever-growing, and it never really helped with any risk mitigation. I would go as far as saying that overall it increased the risk, due to its complexity.
- WorldMaker 3y ago> There is stuff that belongs in releases but should not be present ever in develop branches at all, and vice-versa. Divergence between development branches and release branches may be a sign of stuff that should be configuration-only/environment-configurable and outside of source control. "Build-once, run-everywhere" is a useful mantra: once a version has been cut, if it can be built once and only once and run in every development or release environment, you know that you are stably testing the same build artifacts in your QA environments that you will eventually release. > Also, if you find a bug in a release candidate, you fix that bug alone. You do not add other changes just because someone committed them to the development branch. If you are marking your released versions with git tags then you just build a short-lived branch from the release candidate tag, PR the fix to the short-lived branch (and any long term changes to the main/trunk branch), and cut the bug fix version from the short-lived branch (tag the new version). You don't need long-lived release branches to bug fix older versions and releases.
- WorldMaker 3y ago> Merges are hard to follow and may include conflict resolutions which are hard to show (if they show up at all). My experience is much the opposite. You can follow all the merge parents and three(+)-way diff them with the final merge result to see just the conflict resolutions in a merge. On the other side, tracking down accidental bad conflict resolutions (which result in regressions) in rebased branches is nearly impossible because there's no single commit that just represents the conflict resolutions; depending on the developer doing the rebases they might be smeared across every commit in the entire branch. It gets hard to tell what changes were deliberate and which were conflict resolutions that the developer handled in some way maybe not so deliberately. There are some massive failure cases for regressions I've seen including having to get deep into the woods of git's rerere cache infrastructure and forcing developers to clear that cache so that they stop reintroducing the same kinds of hard to track down regressions in their rebases. (I am grateful that this worst case behavior is rare enough not everyone feels it; I've seen it just enough I prefer that junior developers rarely to never rebase because merge commits preserve more of the process and don't hide the mistakes under the rug.) That said, I definitely agree that short-lived branches and code getting integrated as fast as possible so that conflict resolution is done early and often and as visibly as possible is a good idea.