git cherry-pick -m 1 Explained: How to Pick a Merge Commit

Why You Need -m 1

Cherry-picking a merge commit directly fails: it has two parents, and Git doesn’t know which one to diff against. -m 1 tells Git to “use the first parent (usually the mainline) as the base.”

1
2
3
$ git cherry-pick 8865ad0
error: commit 8865ad060c1c64fbc3c0196e12302b1d96e8bf30 is a merge but no -m option was given.
fatal: cherry-pick failed

The most common scenario: the feature branch has already landed in main through a merge commit, and now you need the same feature on a maintained release branch, without dragging along the other commits on main.

You could cherry-pick each commit from feature one by one, but that gets tedious as the commit count grows, and any conflicts you resolved by hand during the merge won’t come along. Picking the merge commit itself gets you the feature’s complete change in one command.

Core Concept: A Merge Commit Has Two Parents

A regular commit has one parent; a merge commit has two. Parent 1 is the branch you were on when you ran the merge, and parent 2 is the branch that was merged in.

When you run git merge feature on main, the tip of main at that moment becomes parent 1 and the tip of feature becomes parent 2. Merging a PR on GitHub or GitLab with “Create a merge commit” uses the same order: the target branch comes first.

Merge commit M has two parents: C is parent 1, B is parent 2initABCMparent 1parent 2releasefeaturemaintime →
Arrows follow the direction of time: two colored arrows lead into M, one from C (parent 1) and one from B (parent 2).

To confirm the order, look at the Merge: line in the output of git log -1 <sha>. The first hash listed is parent 1:

1
2
3
4
5
6
7
$ git log -1 8865ad0
commit 8865ad060c1c64fbc3c0196e12302b1d96e8bf30
Merge: 06233b4 d9b8793
Author: Demo <[email protected]>
Date:   Fri Jun 26 17:56:50 2026 +0800

    M: merge feature

You can also print each parent with git rev-parse <sha>^1 <sha>^2:

1
2
3
$ git rev-parse 8865ad0^1 8865ad0^2
06233b41967aea22699e607028a268615027526c
d9b87938de6bd17532f3156c05e7cfd0b475a787

What -m 1 and -m 2 Actually Compute

At its core, cherry-pick applies “the diff between a commit and its parent” to the current branch. -m (long form --mainline) just picks one of the two parents as the base. Whichever parent you pick, you take the changes from the other side.

-m 1 diffs C against M and gets login.txt; -m 2 diffs B against M and gets README.md-m 1: base is parent 1 (C)Capp.txtREADME.mddiffMapp.txtREADME.md+ login.txtlands on the current branch+ login.txtfeature's changes (A, B)-m 2: base is parent 2 (B)Bapp.txtlogin.txtdiffMapp.txtlogin.txt+ README.mdlands on the current branch+ README.mdmain-side changes (C)
On the left is the usual -m 1: diffing C against M yields exactly what feature brought in.
OptionBaseDiff computedWhat lands on the current branch
-m 1parent 1 (C, main side)C → MEverything from feature (A, B, plus any conflict resolution done during the merge)
-m 2parent 2 (B, feature side)B → MChanges on main since feature branched off (C)

When the job is “move an already-merged feature to another branch,” you almost always want -m 1.

Hands-On: Build a Demo Repository

You can copy and run the commands below as-is. They build the repository from the diagrams: release stays at init, feature has two commits, main has one unrelated commit, and merge commit M brings feature into main.

We’ll go in four steps and check the commit graph with git log --oneline --graph --all after each one. The output shown is real (your SHAs will differ).

Step 1: Initial commit, branch off release

1
2
3
4
5
6
git init -b main demo && cd demo
echo "v1" > app.txt
git add app.txt && git commit -m "init"

# Branch release off here (we won't touch it again)
git branch release
1
2
$ git log --oneline --graph --all
* f643d1c (HEAD -> main, release) init

There’s only one commit, and both main and release point to it.

Step 2: Two commits on the feature branch

1
2
3
4
5
git checkout -b feature
echo "login" > login.txt
git add login.txt && git commit -m "A: add login"
echo "logout" >> login.txt
git commit -am "B: add logout"
1
2
3
4
$ git log --oneline --graph --all
* d9b8793 (HEAD -> feature) B: add logout
* f7858bc A: add login
* f643d1c (release, main) init

feature has moved two commits ahead; main and release are still at init.

Step 3: An unrelated commit on main

1
2
3
git checkout main
echo "readme" > README.md
git add README.md && git commit -m "C: add readme"
1
2
3
4
5
6
$ git log --oneline --graph --all
* d9b8793 (feature) B: add logout
* f7858bc A: add login
| * 06233b4 (HEAD -> main) C: add readme
|/
* f643d1c (release) init

History forks after init: feature’s A and B on one side, main’s C on the other.

Step 4: Merge feature into main with a merge commit

1
git merge --no-ff feature -m "M: merge feature"

--no-ff guarantees that a merge commit is created.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ git merge --no-ff feature -m "M: merge feature"
Merge made by the 'ort' strategy.
 login.txt | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 login.txt
$ git log --oneline --graph --all
*   8865ad0 (HEAD -> main) M: merge feature
|\
| * d9b8793 (feature) B: add logout
| * f7858bc A: add login
* | 06233b4 C: add readme
|/
* f643d1c (release) init

Two lines lead into M (8865ad0): the vertical one from C (06233b4, parent 1) and the one on the right from B (d9b8793, parent 2). That’s the same order as Merge: 06233b4 d9b8793 earlier.

Run the Cherry-Pick and Verify

Switch to release and pick M with -m 1. Since main currently points at M, you can use the branch name directly:

1
2
git checkout release
git cherry-pick -m 1 main      # same as git cherry-pick -m 1 8865ad0

Running it and checking the result in the terminal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ git checkout release
Switched to branch 'release'
$ git cherry-pick -m 1 main
[release 20de01d] M: merge feature
 Date: Fri Jun 26 17:56:50 2026 +0800
 1 file changed, 2 insertions(+)
 create mode 100644 login.txt
$ ls
app.txt  login.txt
$ git log --oneline --graph --all
*   8865ad0 (main) M: merge feature
|\
| * d9b8793 (feature) B: add logout
| * f7858bc A: add login
* | 06233b4 C: add readme
|/
| * 20de01d (HEAD -> release) M: merge feature
|/
* f643d1c init
$ git log -1 --format='%h parents: %p'
20de01d parents: f643d1c

release got feature’s login.txt, and main’s README.md did not come along. Note that the new 20de01d is an ordinary single-parent commit (its only parent is f643d1c), not a merge commit. It just reuses M’s commit message.

Comparison: What Happens with -m 2

With -m 2 you get main’s README.md instead, and none of feature’s changes. Try it on a fresh branch from init:

1
2
git checkout -b release-m2 release~1   # back to init, before the cherry-pick
git cherry-pick -m 2 main
1
2
3
4
5
6
7
8
9
$ git checkout -b release-m2 release~1
Switched to a new branch 'release-m2'
$ git cherry-pick -m 2 main
[release-m2 220b106] M: merge feature
 Date: Fri Jun 26 17:56:50 2026 +0800
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
$ ls
README.md  app.txt

The base is now B. B already contains login.txt, so the diff from B to M is only the README.md that C introduced.

-m 2 still has its uses. If someone first ran git merge main on feature and then fast-forwarded main to that merge, the parent order is reversed, and you’d need -m 2 to get feature’s changes.

Common Pitfalls and Best Practices

The biggest pitfall is assuming parent 1 is the mainline. Confirm the parent order before you act, and the rest is easy to handle.

  • Check the order first. Use the Merge: line from git log -1 <sha> to confirm which one is parent 1, especially for merges someone else made.
  • Add -x to record the source. git cherry-pick -x -m 1 <sha> appends (cherry picked from commit ...) to the commit message, so you can find where a change came from later.
  • Handle conflicts as usual. Fix the conflicted files, git add them, then run git cherry-pick --continue. To give up, git cherry-pick --abort puts the branch back where it was.
  • Watch out for later merges. Cherry-pick creates new SHAs, and Git doesn’t remember that these changes are already in release. If you later merge feature or main into release, identical changes usually merge cleanly, but anything feature changed afterwards may conflict.
  • Reverting works differently. A cherry-picked commit is a regular commit, so git revert <new sha> is enough. Reverting the original merge commit M needs git revert -m 1 M too.
  • You can apply -m 1 to a whole batch. Since Git 2.21, -m also works on regular commits, so a range that includes merge commits can be picked with one command.

With -x, the last line of the commit message records the full SHA of the source merge commit:

1
2
git checkout -b release-x release~1
git cherry-pick -x -m 1 main
1
2
3
4
5
6
7
8
$ git log -1
commit bd76f2d148bac366ad55b388915292d25daead59
Author: Demo <[email protected]>
Date:   Fri Jun 26 17:56:50 2026 +0800

    M: merge feature

    (cherry picked from commit 8865ad060c1c64fbc3c0196e12302b1d96e8bf30)

Cheat Sheet

The one thing to remember: -m N uses the Nth parent as the base and takes the changes from the other side. To move a merged feature, use -m 1.

CommandWhat it does
git cherry-pick -m 1 <M>Apply M’s diff against parent 1 (the merged-in branch’s changes) to the current branch
git cherry-pick -m 2 <M>Apply M’s diff against parent 2 (the mainline side’s changes) to the current branch
git cherry-pick -x -m 1 <M>Same as above, and record the source SHA in the commit message
git log -1 <M>Show the Merge: line to confirm the parent order
git rev-parse <M>^1 <M>^2Print parent 1 and parent 2
git cherry-pick --continueContinue after resolving conflicts and running git add
git cherry-pick --abortAbandon this cherry-pick and return to the previous state
git revert -m 1 <M>Revert everything the merge brought in
Built with Hugo
Theme Stack designed by Jimmy