Table of Contents

Introduction

If you've ever resolved a merge conflict, you know the moment afterwards where you stare at the terminal wondering what Git wants from you next. The conflict markers are gone, the file looks right, and the merge is still hanging open. git merge --continue is the command that closes it: it makes the merge commit Git stopped short of making, with your resolution in it.

In this article, we'll:

  1. Resolve the styles.css conflict from a merge of feature into main
  2. Watch git merge --continue create the merge commit and move main onto it
  3. Cover the commit message editor, --no-edit, and how --continue relates to plain git commit

What is git merge --continue?

git merge --continue concludes a merge that stopped on a conflict. It checks that a merge is in progress (that .git/MERGE_HEAD exists), and then runs git commit. Because MERGE_HEAD is there, that commit gets two parents: the commit you were on and the tip of the branch you merged in. Your branch and HEAD move to the new commit, just as they would after a merge that never conflicted.

It commits whatever is staged, so it won't run while any file is still unmerged. Git tells you to fix the conflicts first.

Resolving the conflict

Our sample repo has a merge of feature into main that stopped on a conflict in styles.css, now resolved and staged. On main, "Switch the header to grid" (ada2e79) set styles.css to header { display: grid; }. On feature, "Space out the header links" (791fd8e) set it to header { display: flex; gap: 12px; }. When the merge stopped, the file held both, between conflict markers:

<<<<<<< HEAD
header { display: grid; }
=======
header { display: flex; gap: 12px; }
>>>>>>> feature

Resolving it takes three steps. First, edit the file into what you actually want and delete the markers. Here we keep the grid from main and the gap from feature:

header { display: grid; gap: 12px; }

Second, stage it with git add. Staging is how you tell Git "this file is resolved". There's no separate command for that. git status then says:

All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Third, run git merge --continue.

Watch it happen

Here's git merge --continue, with the resolution staged:

  1. Before: main and HEAD point at ada2e79 "Switch the header to grid", and feature points at 791fd8e "Space out the header links". The resolution is staged, but it isn't a commit yet.
  2. Git creates the merge commit, "Merge branch 'feature'", with two parents: ada2e79, main's old tip, and 791fd8e, feature's tip.
  3. main and HEAD move to the merge commit. feature stays where it was.

Before and after

Before, the branches diverge at "Fix header layout" (96c4fc2) and nothing joins them. After, the merge commit ties them back together and sits at the tip of main. Git prints one line, the new commit:

The raw git output, if you want to read along in text

git log --oneline --graph --all

before

* 791fd8e (feature) Space out the header links
* 1117a34 Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * ada2e79 (HEAD -> main) Switch the header to grid
| * 8c02d5b Update dependencies
| * a0b2db3 Add user settings page
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

after

*   82607fd (HEAD -> main) Merge branch 'feature'
|\  
| * 791fd8e (feature) Space out the header links
| * 1117a34 Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
* | ada2e79 Switch the header to grid
* | 8c02d5b Update dependencies
* | a0b2db3 Add user settings page
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

what git printed

[main 82607fd] Merge branch 'feature'

In the after log, 82607fd is the merge commit, and the |\ below it is git log drawing its second parent. git status goes from M styles.css plus the two new files from feature staged, to clean.

Is it safe?

Safe git-sim pre-flight

Creates the merge commit with your resolution; main moves to it.

The way back

  • Undo the new commit afterwards with: git reset --hard ORIG_HEAD

It is. It adds a commit and moves main forward, and nothing is deleted. The only thing to check is that you really did resolve everything, since --continue commits whatever is staged. A file you staged with the conflict markers still in it will go into the merge commit that way. A quick git diff --staged before continuing catches that.

For years I finished every conflicted merge with plain git commit, because that's what git status tells you to do and --continue didn't exist for merges until Git 2.12 in 2017. I've switched mostly for consistency: rebase and cherry-pick already had --continue, and it's nice to type the same thing no matter which one stopped.

How to undo it

If you haven't pushed, move main back to its first parent, the commit it was on before the merge:

git reset --hard HEAD~1

HEAD~1 follows the first parent, which for this merge is ada2e79. The merge commit drops off main, and your working directory goes back to the grid-only styles.css. Keep in mind --hard also discards any uncommitted edits you've made since.

If the merge has already been pushed and others have it, add a commit that reverses it instead, with git revert -m 1.

The editor and --no-edit

git merge --continue opens your editor with a message ready to go: "Merge branch 'feature'", followed by a commented list of the files that conflicted. Save and close to accept it, or write something that says how you resolved the conflict. That's a good place to note that you kept the grid and took the gap.

To skip the editor, you might reach for git merge --continue --no-edit, but --continue takes no other options and Git will refuse with "--continue expects no arguments". Use git commit directly instead, which does accept it:

git commit --no-edit

Useful forms

  • Plain git commit does the same thing as git merge --continue while a merge is in progress. --continue just checks first that there is a merge to continue.
  • git commit -m "Merge feature, keep grid with the new gap" finishes the merge with a message of your own.
  • git merge --abort gives up on the merge instead, if the resolution is going badly.

Try it on your repository

pip install git-sim
git-sim merge --continue

git-sim runs the command in a copy of your repository and draws the merge commit it would make, so your own half-finished merge is left alone.

Common questions

What does git merge --continue do?

It finishes a merge that stopped on a conflict, once you've resolved and staged every conflicted file. It creates the merge commit with two parents and moves your branch onto it.

Is git merge --continue the same as git commit?

Almost. With a merge in progress, git merge --continue runs git commit for you. The difference is that it fails if no merge is in progress, and it doesn't accept options like -m or --no-edit.

How do I mark a merge conflict as resolved?

Edit the file to remove the conflict markers, then git add it. There's no separate "resolved" command. The git merge documentation lists the tools that can help, like git mergetool.

Why does git merge --continue say I still have unmerged files?

At least one file is still marked as conflicted. git status lists it under "Unmerged paths". Resolve it and git add it, then continue.

Summary

In this article, we resolved the styles.css conflict by hand, staged it, and watched git merge --continue create "Merge branch 'feature'" with parents ada2e79 and 791fd8e and move main and HEAD onto it.

Next steps

git merge --abort is the way out when you'd rather not resolve the conflict right now. git merge covers merges that never stop at all.