In our team's repository, we work by submitting PRs and we only merge them into master using github's squash & merge functionality. The problem for me is that I can then no longer see branches merged into master with git branch --merged
, as this will not show branches that have been squashed & merged. My local branches are piling up and it's a pain to review them one by one to see which I can remove. Is there another way to list them?
You can use the git merge-base command to find the latest common commit between the two branches. If that commit is the same as your branch head, then the branch has been completely merged.
With git branch --merged <commit> , your local list of branches will be filtered by all the branches who have been merged into a given branch or commit. Similar to above, you could type git branch --no-merged <commit> and only the branches not merged into the named commit would be listed.
tl;dr; Unfortunately, no. You'll have to check the status of your PR on GitHub and, once it has been merged, forcibly delete your local branches with git branch -D
.
The GitHub Squash and merge operation doesn't actually merge your topic branch ― instead, it squashes all the commits from that branch into a single one, and then rebases that commit on top of the target branch.
From the documentation:
When you select the Squash and merge option on a pull request on GitHub, the pull request's commits are squashed into a single commit.
And the most important part:
Pull requests with squashed commits are merged using the fast-forward option.
A fast-forward merge doesn't create a merge commit ― it simply moves the target branch reference forward so that it points to the same commit as the source branch. This can only be done if the source branch points to a commit that is a descendant of the target branch.
So, if your topic branch looks like this in your local repository:
master
v
o--o--o--o
\
A--B--C <- This is the branch you want to merge with a PR
^
topic
When you use Squash and merge, GitHub will rewrite the history of your topic
branch so that it looks like this:
master
v
o--o--o--o
\
S <- This is A, B and C squashed together
^
topic
Then, GitHub will rebase topic
on top of master
. Notice that this will result in a commit that's different from the original squashed commit S
because of the different parent; to distinguish it, we call the rebased commit S'
(S prime):
master
v
o--o--o--o
\
S'
^
topic
Finally, the topic
branch is incorporated into master
with a fast-forward merge:
master
v
o--o--o--o--S'
^
topic
This all happens inside the repository that's hosted on GitHub's servers. Meanwhile, on your machine the repository still looks like this:
master
v
o--o--o--o
\
A--B--C
^
topic
After you've done git pull
on master
, you'll receive the squashed and rebased commit S'
:
master
v
o--o--o--o--S'
\
A--B--C
^
topic
Git has no way of knowing that commit S'
contains the combined changes from A
, B
and C
. That's why it will still report topic
as unmerged.
Linus Torvalds once wrote:
People can (and probably should) rebase their private trees (their own work). That's a cleanup. But never other peoples code. That's a "destroy history".
He then continues:
You must never EVER destroy other peoples history. You must not rebase commits other people did. Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours.
It should be obvious that GitHub's Squash and merge feature destroys other people's history by completely rewriting their PR branches.
I won't sit here and tell you that Squash and merge is intrinsically evil ― I'm sure it has its uses.
However, if your team often finds itself having to deal with stale local branches (like you described), you might want to consider switching to a merge workflow that incorporates the history of your PRs as-is instead of destroying it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With