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 ...
#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 '[email protected]: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
