Use git cherry to Find Patches Still Missing Upstream
You will finish with a safe way to identify which commits on a topic branch are still absent from an upstream branch, even when the maintainer has already applied some of them with a different commit ID. Allow about ten minutes. You need Git 2.43.0 or a compatible Git installation and a local repository with a topic branch and an upstream reference. The commands below only inspect history, except for git fetch, which updates your local remote-tracking references.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check Git and the branch context
Run this from the repository that contains the work you want to compare:
$ git --version
git version 2.43.0
$ git branch --show-current
topic
$ git branch -vv
* topic d77ee9a [origin/main: ahead 1] add the second change
The version shown here is the installed version on this machine. The local manual page is for Git 2.43.0. The current upstream documentation keeps the same syntax and says the command has no documented changes between Git 2.1.4 and 2.55.0, but a different Git build can still produce different surrounding branch names or subjects.
Checkpoint: confirm that you are in the intended repository and that git branch --show-current names the branch whose commits you want to examine. git cherry does not publish, delete or rewrite commits, but running it in the wrong repository can still lead you to make the wrong later decision.
2. Refresh the upstream reference
If the upstream is a remote branch, update your local view before comparing it:
$ git fetch origin
This is an ordinary, unprivileged command. It updates remote-tracking refs such as origin/main; it does not merge them into your working branch and does not modify tracked files in your worktree. If your repository uses a different remote, replace origin with that remote name.
Verify the names that are available:
$ git branch -a
* topic
main
remotes/origin/main
Do not invent origin/main if your project uses another branch. Use the exact ref printed by git branch -a, or inspect the configured upstream with:
$ git rev-parse --abbrev-ref @{upstream}
origin/main
3. Run the comparison
Give git cherry the upstream first and your topic branch second:
$ git cherry -v origin/main topic
- 3f2a1b7... add support for the old format
+ d77ee9a... add the second change
A line beginning with - means the topic commit has an equivalent patch in the upstream history. A line beginning with + means no equivalent patch was found upstream. With -v, Git prints a shortened object ID and the commit subject. Without it, the output is just the sign and object ID:
$ git cherry origin/main topic
- 3f2a1b7
+ d77ee9a
The comparison is patch-based. Git compares the diffs after removing whitespace and line-number information, so a cherry-picked or rebased change can match despite having a different commit ID. This is why the result is more useful for patch-based workflows than a simple check for whether one commit hash appears in both histories.
4. Let Git use the configured upstream
When the current branch tracks an upstream branch, you can omit both branch arguments:
$ git cherry -v
- 3f2a1b7... add support for the old format
+ d77ee9a... add the second change
Here, origin/main is the configured upstream of topic, and HEAD is the topic branch. The default is not necessarily the branch you call "main" in conversation. Check it with git rev-parse --abbrev-ref @{upstream} before relying on the shorthand.
If Git reports that the current branch has no upstream, use explicit refs:
$ git cherry -v origin/main HEAD
This form avoids changing branch configuration just to perform a read-only check. You can configure tracking separately with git branch --set-upstream-to=origin/main topic if that relationship is correct for your project.
5. Limit the range when the topic has a private base
The optional third argument, limit, excludes that commit and everything reachable before it from the report. This is useful when a topic includes preparatory work that is not intended for the upstream maintainer.
$ git log --oneline --decorate origin/main..topic
d77ee9a (HEAD -> topic) add the second change
3f2a1b7 add support for the old format
91c0b44 private test fixture
$ git cherry -v origin/main topic 91c0b44
- 3f2a1b7... add support for the old format
+ d77ee9a... add the second change
Choose the limit from the actual graph, rather than assuming that HEAD~2 is the right boundary after merges or rebases. git log --graph --oneline --decorate --all is a useful read-only check when the history is not linear.
6. Decide what to send or drop
Usually, retain the + commits for the next patch series. The - commits already have equivalent changes upstream, so sending them again risks duplicate work. Treat this as evidence for a review, not an automatic instruction to rewrite the branch.
Rebasing or dropping commits changes history and may disrupt collaborators. Before doing that, save or share the branch as appropriate. If you later lose a local commit during an accidental rewrite, git reflog can often show the previous branch tip, and git branch recovery-name <old-object-id> can preserve it before further work. Recovery depends on the object still being present, so do not treat the reflog as a permanent backup.
No elevated privileges are required for these Git commands. Do not use sudo to inspect a repository. If permissions prevent access, fix ownership or repository access through your normal administration process rather than creating root-owned files in the working tree.
Common traps
- Reading the sign backwards:
-means equivalent upstream work was found;+means the topic patch is not found upstream. - Comparing stale data: run
git fetchbefore checking a remote branch if the maintainer may have applied a patch recently. - Using the wrong order: the syntax is
git cherry [upstream] [head] [limit], not topic first. - Expecting identical hashes: patch equivalence is designed to recognise cherry-picks, rebases and mail-applied patches with new IDs.
- Assuming a clean result means identical history: whitespace and line-number removal affect the equivalence test, so review the actual diff when a decision matters.
Done means
- The upstream ref was verified and refreshed where necessary.
git cherry -vor its explicit form was run from the intended topic branch.-entries were treated as already-applied patches and+entries as remaining work.- A private base was excluded with an explicit, graph-checked limit when needed.
- No branch rewrite, deletion or privileged command was performed merely to inspect patch status.