Reputation: 641
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?
Upvotes: 14
Views: 1759
Reputation: 89053
You can use the gh
command line tool for this:
$ gh pr list -s merged --json headRefName -q '.[].headRefName' |
sort -k 1,1 |
join <(git branch | sort -k 1,1) -
gh pr list ...
will display the branch names used when a commit was merged; we can compare it with the local list of branch names from git branch
using the join
command, though we need to sort
both lists first.
More conservatively, you could check which ones match based on commit object id, rather than on the name:
$ gh pr list -s merged --json headRefOid -q '.[].headRefOid' |
sort -k1,1 |
join <(git branch --format '%(objectname) %(refname:short)' | sort -k1,1) -
Upvotes: 1
Reputation: 7146
I came accross the same problem using PRs and squash merges and made a small command to cleanup the undesired branches, based on the ones that had an upstream branch.
It also avoids main branches deletion like master
, develop
, and release
:
git branch -d $(git branch --format "%(refname:short) %(upstream)" | awk '{if ($2) print $1;}' | grep -vE "release|develop|master") -f
I made it using the answer to this question : List all local branches without a remote
Upvotes: 0
Reputation: 59913
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.
Upvotes: 8