git branch --merged does not show all merged branches [SOLVED]
April 5th, 2023 | 4 mins read
In git, you can display the list of all branches you have locally with the
git branch command. This command also supports a list of options that determines how the result is displayed.
One of those options is
git branch --merged
By using this option with the branch command, you get a list of all branches that have been merged to
HEAD, which is the active branch when the command is run. You can explicitly specify a target branch like this:
git branch --merged main
This will show a list of all branches that have been merged to
main. The branches listed would also include
main because the changes in
main have been merged into
TLDR: if the state of the remote branch is different from the local branch, and the remote branch is merged to a target branch, git would not be able to verify if the local branch has been merged to the target branch
Recently, I ran this merged command, but I didn't get the list of merged branches I expected.
My scenario was that I had some local branches which were synced with remote branches. Those remote branches were merged with main. So I pulled main:
git pull origin main
But when I ran
git branch --merged, I didn't see the list of local branches which I expected. What I discovered (hours later) was that the state of the local branches were not in sync with the state of the remote branches when the remote branches were merged.
What makes the state of a local branch different from its remote counterpart?
Something might have happened to the branch on remote which didn't happen locally, and that would put the branches out of sync. If this happened before the remote branch was merged, git would be unable to tell if the branch has been merged locally.
I experienced this while using a "rebase and fast-forward" merge approach.
My setup is like this: for merge requests, I don't do the regular merging which adds a new commit when a branch is merged with another branch. Instead, I use the fast-forward merge which adds only the commits made in the branch I want to merge, without including a "merge commit".
But fast-forwards are only possible if the branch I want to merge (let's call it
testing) contains all changes in the target branch (let's call it
main). So if I have already made new changes on
main since the time
testing was created, a fast-forward merge for
main won't work.
For a fast-forward merge to work, I'd have to rebase
main. And when that works successfully,
testing would contain all the changes in
main (with the new changes added on top), and a fast-forward merge would work. I can easily perform a rebase on the GitLab UI (without having to do that locally) so that my merge can be successful.
So here is where the git history of the new branch on remote becomes out of sync with the local branch.
By rebasing on the GitLab UI (which I had to do as there were new changes on
main) before merging, the state of the remote
testing branch changes. The remote branch now contains the new changes made on
main. But that's not the case with the local
testing branch right?
Because I didn't rebase locally, the local branch only contains changes from
main which existed before the branch was created. It doesn't contain new changes on
main that are made afterwards.
What do you notice here? The remote
testing branch and local
testing branch are now in different states.
So, the remote branch is merged, and then you sync the remote
main branch with the local
main branch (by
Now, even if the local
main branch now contains the new changes you made in
git branch --merged won't show you
testing, because the state of the remote
testing branch before it was merged was different from the local
However, if you check "remote branches that are merged", you would see the remote testing branch:
git branch -r --merged
r option shows only remote branches in the result.
So how do you fix this for the local branch?
To solve this, you have to ensure that the local
testing branch is synced with the remote
testing branch. By doing that, the local branch would have the same state as the remote branch, and then, git can verify that the branch has indeed been merged.
Here are two ways you can ensure the branches are synced.
Remember that what changed the state of the remote branch was the fact that it was rebased with
main. We can repeat that for the local branch. For example:
git checkout testing git rebase main
This would put the local
testing branch in the same state as the remote
Now when you run
git branch --merged,
testing would be listed as a merged branch.
Instead of rebasing, you can also sync the remote branch with the local branch, by pulling:
git checkout testing git pull origin testing
But this would throw an error. The reason for this is that your branches are out of sync--they have diverged. You may see a similar error from git like this:
The reason for this error, again, is that both branches are in different states. So you can't automatically do a push.
As you see in the hints, git recommends a rebase. So we can rebase the local branch with the remote by using this command:
git rebase origin/testing
testing remote and local branches are now in the same state, so when you run
git branch --merged, you'd see
This problem does not only occur in fast-forward merges. It can also occur if you're using the squash and merge approach. If all commits in a branch (say,
testing) are squashed into one commit during merge, git would not be able to tell if
testing was merged with the target branch by executing
git branch --merged.
That's because, even though all the content changes in
testing exist in the target branch, the histories are different. The target branch has only one commit with all the changes, while
testing has multiple commits with the changes. Hence, git would not be able to tell.
As for this, I don't know the solution, but when I discover it, I'll share :)
If you enjoyed or learn anything from this piece, please share with others 😇