Intro
I prefer maintaining a linear Git history, where features are added in traceable portions. This approach has many benefits, as it makes it easy to track what has happened earlier in the project. Such a workflow often necessitates the frequent use of Git rebase capabilities, including:
- Rebasing the feature branch into a coherent feature chunk.
- Rebasing it against the main branch to keep it on top of other changes.
- And so on.
Another Git/Git-service feature I appreciate is the ability to sign commits, which UI-wise results in a green "Verified" label on the Git-service's UI. This adds an extra layer of trust regarding the identity of the commit/feature submitter.
Every major Git service provider, including GitLab, BitBucket, and GitHub, supports this workflow. Or do they?
The Problem:
To be honest, GitHub has a issue in this regard. In short, when performing a rebase action in the GitHub UI, it will rewrite your commits, even if the feature branch could be merged without merge commits. This means you will lose your signed verification signature — quite a horror!
Note, Other major platforms will perform the expected fast-forward-only merge in the same case, meaning they won't create any merge commits. This allows you to simply add the commit on top of the main branch, preserving the signature.
This is a known GitHub-problem, as evidenced by discussions at GitHub Community and Stack Overflow.
GitHub has also acknowledged this issue with their platform. It is highlighted in their documentation and has received a response from their support:
This is a known issue we are tracking internally and a pain point for a number of folks....
Currently, reverted pull requests created from a previously squash and merge pull request or a rebase and merge pull request are indeed not signed...
While we don’t yet have a specific ETA for when this might be implemented...
Pain point?! YES!
The Workaround:
So, what can you do? Just follow their advice in their documentation: "A workaround for this is to rebase and merge locally, and then push the changes to the pull request's base branch." Aha, seems easy in words, but how can you translate this into terminal commands?
For example, if you have a pull request that you are ready to merge:
First, fetch the pull request locally by creating a feature branch for it.
git fetch origin pull/<PULL-REQUEST-NUMBER>/head:<NAME-YOU-WANT-THE-PR-BRANCH-TO-HAVE-LOCALLY>
Then, while on your base branch i.e main, merge the locally fetched PR branch into it.
git merge --ff-only <THE-LOCAL-PR-BRANCH>
Finally, push it to the base branch.
git push
GitHub will now close the pull request as merged, and you will have a clean commit history with the signed commit intact.
The Summary:
Is pushing to the main branch a hackish? Yes, but until GitHub fixes this problem, it is the only way and they recommend it in the documentation.
Other
Other Git related articles on DEV from me:
Git signing and signoff like a champ
A clean Git history with Git Rebase and Conventional Commits
Top comments (2)
I too would rather avoid complicated graphs in my git histories. However, I see value in the merge commits as they very clearly show the "two brains" principle, and retain context for sets of commits.
Here is a sample for the Standard for Public Code:
In the above, it can easily be seen that for each contribution one person created a change and another person reviewed and merged it.
Also the logical grouping of sets of commits are retained, as in the case of the 3 roadmap related commits by Ainali.
While not perfectly linear (as long as there is a rebase before merge) the commit history remains easy to understand and remains linear from a
git bisect
perspective.I'm a bit boring here in my answer as I must say I agree here Eric. Merge commits has it's merits, and it's easy to skip them if the need arises for autogeneration of Changelogs etc. Like much things in our development sphere is comes down to developer or team tastes at times. The important thing is that the project has some agreement as how they want it, it and then it is not as important as how what they want is achieved.