Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
Frame challenge, the "bubbles" aren't useless First off, I'll challenge the premise of the question: the "merge bubbles" are not useless, because they represent meaningful development history. In ...
Answer
#1: Initial revision
### Frame challenge, the "bubbles" aren't useless First off, I'll challenge the premise of the question: the "merge bubbles" are not useless, because they represent meaningful development history. In particular, given the toplogy below: ```text A -- B -- C -- H <- master \ \ / D -- E -- F <- topic ``` Commit _F_ may include non-trivial resolutions to merge-conflicts, and commit _H_ will be a trivial merge. There's an argument to be made that these conflict resolutions _belong_ in the topic branch, and not in master's first-parent ancestors. In any case, master's first-parent ancestors will still contain exactly one commit (_H_) neatly representing all the changes from the topic branch. The most obvious alternative topology is a "trapezoid" topology: ```text v- master A -- B -- C -- F <- topic \ / D -- E ----/ ``` In this case, when _topic_ is merged into _master_, _master_ will fast-forward to _F_, and _C_ will be _master's_ first parent, but this topology has some downsides. For instance, if you create a new commit (_G_) on master in the meantime, you will end up with an even stranger topology when topic is merged back to master: ```text A -- B -- C -- G -- H <- master \ \ / \ \---- F <- topic \ / \----- D -- E ``` Since _master_ can no longer be fast-forwarded, a new merge commit (_H_) needs to be created. On the other hand if you used a "rhombus" topology, you would end up with the nicer looking: ```text A -- B -- C -- G -- H <- master \ \ / D -- E -- F ----/ <- topic ``` ### But if you still don't want bubbles #### Avoid making them You can avoid "rhombus" topologies and "useless bubbles" by merging the _topic_ into the commit pointed to by _master_ instead of merging _master_ into the _topic_ branch. Then when _master_ gets fast-forwarded, its first parent will be the commit previously pointed to by _master_. This isn't a common workflow, so while there are a few ways to perform this "reverse" merge, none of them are straightforward. One method would be: ```sh git switch --detach master git merge topic git update-ref refs/heads/topic HEAD git switch topic ``` In English, that process is: 1. Switch to _master_, but with a detached HEAD so we don't later change which commit _master_ points to 2. Merge in _topic_. Now we have a commit whose first parent is _master_ and whose second parent is _topic_. 3. Update _topic_ to point to the new commit 4. Switch back to _topic_. You might consider [configuring][1] (and distributing) a [Git alias][2] to make this process easier. #### Avoid taking them You can have the server reject such bubbles by creating an "update" server-side [Git hook][3]. For example, you may use a shell script like below for the hook: ```sh #!/usr/bin/sh ref="$1" old_commit="$2" new_commit="$3" grandparent=$(git rev-parse --verify --quiet "$new_commit^2^2" || :) if [ "$grandparent" = "$old_commit" ]; then printf "%s\n" \ 'Useless bubble detected' \ 'Please `git reset --hard HEAD^` then "reverse" merge' exit 1 fi ``` If anyone tries to push commit _G_, the server will reject their push, and they'll receive a message like: ```text remote: Useless bubble detected remote: Please `git reset --hard HEAD^` then "reverse" merge remote: error: hook declined to update refs/heads/master To /tmp/git-remote ! [remote rejected] master -> master (hook declined) error: failed to push some refs to 'user@example.com:example.git' ``` [1]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-alias [2]: https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases [3]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks