Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display local branches that have been "squashed & merged" into master

Tags:

git

branch

github

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?

like image 709
Le Frite Avatar asked Aug 28 '19 07:08

Le Frite


People also ask

How do you see if a branch has been merged?

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.

How do I see local branches with merged work?

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.


1 Answers

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.

"Squash and merge" Illustrated

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.

A Practical Consideration

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.

like image 168
Enrico Campidoglio Avatar answered Sep 25 '22 18:09

Enrico Campidoglio