Git History Needs a Higher Level

Posted on May 1, 2021

Have you ever been trying to understand the history of a git versioned project, or file and immediately gotten frustrated because it is hard to follow changes through commits like “fixed formatting”? These commits provide no information about the important changes to the file, but are necessary when there are automated code formatting checks that prevent merging changes (a good thing to have). Next you go to the pull/merge request section and try to understand the changes there, but to see the files that were changed in that merge you have to click into every request, so you cannot get your answer quickly and easily here either. The problem here is with the level at which git surfaces history.

Git surfaces history at the change level, the commit, not the finished change level, the merge. Unfortunately what we care about when looking at the history of a project is the finished change. The completed fix, or feature that was added to the code base.

GitHub, GitLab, and maybe other git hosts I have not used, understand this. It is why they are set up to do code reviews at the merge level though Pull Request and Merge Requests respectively. Unfortunately this does not solve the problem of understanding the history of the project. If anything it exacerbates the problem by normalizing looking at code at the merge level, but displaying history at the commit level.

There are a couple of ways to fix this. One is to show file history at the merge level. The other is to have one commit per merge. The key is being able to see history at a complete change level instead of a partial change level.

One commit per merge is technically possible in git. You can use squash and merge, or you can reset head and recommit changes as you continue to make updates. Unfortunately git is not designed to work this way, so these actions cause problems in the workflow. When you create a branch off of a branch squashing and merging the first branch when you merge it will result in merge conflicts in its child branch. When you git reset HEAD~1 and git push --force anyone else working on the branch can no longer simply pull your changes. Commit level history can also be useful at times, for example when reviewing code.

There are alternative source control management tools that implement workflows more like this, such as Mercurial , but the widespread use of and tooling that has sprung up around git make it hard to abandon. The ideal solution is for git to record merges into the default branch and be able to display this higher level history in a log. This requires no changes in existing workflows, no information is lost, and a new, high level, change history becomes visible.