-
Notifications
You must be signed in to change notification settings - Fork 202
[doc] Add new page on merge conflicts #2237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
ad4853d
a1686a2
128d69e
ab45923
03a6b43
d3904f0
4505fdc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,25 +19,9 @@ Given one or more existing commits, apply the change each one | |
| introduces, recording a new commit for each. This requires your | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Junio C Hamano wrote on the Git mailing list (how to reply to this email): "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Julia Evans <julia@jvns.ca>
>
> Remove the discussion of merge conflicts and replace it with a link to
> the guide.
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
> Documentation/git-cherry-pick.adoc | 23 ++++-------------------
> 1 file changed, 4 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/git-cherry-pick.adoc b/Documentation/git-cherry-pick.adoc
> index f4cd8b9db7..d93829600b 100644
> --- a/Documentation/git-cherry-pick.adoc
> +++ b/Documentation/git-cherry-pick.adoc
> @@ -19,25 +19,9 @@ Given one or more existing commits, apply the change each one
> introduces, recording a new commit for each. This requires your
> working tree to be clean (no modifications from the HEAD commit).
>
> -When it is not obvious how to apply a change, the following
> -happens:
> -
> -1. The current branch and `HEAD` pointer stay at the last commit
> - successfully made.
> -2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that
> - introduced the change that is difficult to apply, unless the
> - `--no-commit` option was given.
> -3. Paths in which the change applied cleanly are updated both
> - in the index file and in your working tree.
> -4. For conflicting paths, the index file records up to three
> - versions, as described in the "TRUE MERGE" section of
> - linkgit:git-merge[1]. The working tree files will include
> - a description of the conflict bracketed by the usual
> - conflict markers `<<<<<<<` and `>>>>>>>`.
> -5. No other modifications are made.
> -
> -See linkgit:git-merge[1] for some hints on resolving such
> -conflicts.
> +When it is not obvious how to apply a change, there may
> +be a merge conflict. See linkgit:gitmergeconflicts[7]
> +(or `git help mergeconflicts`) for a guide to handling merge conflicts.
The new document may explain how to resolve conflicts, but are the
details removed from here that are specific to the 'cherry-pick'
operation also covered there?
For example, during a difficult cherry-pick, it is often handy to be
able to run 'git show CHERRY_PICK_HEAD', but now users are not told
about the pseudo-ref, which seems like a real loss.
The fact that cleanly auto-resolved contents for paths are recorded
in the index may be shared with all other merge-like operations,
and it need not be part of the "how to resolve a conflicted
merge-like operation" recipe, but users need to be assured that this
is what happens somewhere in the documentation set. The list
removed here served that purpose for this specific command, but it
is now gone.
I do not recall offhand whether we explicitly tell our users that
all merge-like operations update the index with cleanly auto-resolved
results and only leave conflicts to be hand-resolved by the user,
but even if we did so elsewhere, I do not see any reference to that
in the existing text of the 'cherry-pick' manual, nor does this
patch series add such a link. At least item #2 and #3 should be
kept in the list, I think. A better alternative might be to add
your new reference, and shorten the description given in item #4,
and leave everything else as before.
Thanks.
>
> OPTIONS
> -------
> @@ -259,6 +243,7 @@ $ git cherry-pick -Xpatience topic^ <4>
> SEE ALSO
> --------
> linkgit:git-revert[1]
> +linkgit:gitmergeconflicts[7]
>
> GIT
> --- |
||
| working tree to be clean (no modifications from the HEAD commit). | ||
|
|
||
| When it is not obvious how to apply a change, the following | ||
| happens: | ||
|
|
||
| 1. The current branch and `HEAD` pointer stay at the last commit | ||
| successfully made. | ||
| 2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that | ||
| introduced the change that is difficult to apply, unless the | ||
| `--no-commit` option was given. | ||
| 3. Paths in which the change applied cleanly are updated both | ||
| in the index file and in your working tree. | ||
| 4. For conflicting paths, the index file records up to three | ||
| versions, as described in the "TRUE MERGE" section of | ||
| linkgit:git-merge[1]. The working tree files will include | ||
| a description of the conflict bracketed by the usual | ||
| conflict markers `<<<<<<<` and `>>>>>>>`. | ||
| 5. No other modifications are made. | ||
|
|
||
| See linkgit:git-merge[1] for some hints on resolving such | ||
| conflicts. | ||
| When it is not obvious how to apply a change, there may | ||
| be a merge conflict. See linkgit:gitmergeconflicts[7] | ||
| (or `git help mergeconflicts`) for a guide to handling merge conflicts. | ||
|
|
||
| OPTIONS | ||
| ------- | ||
|
|
@@ -259,6 +243,7 @@ $ git cherry-pick -Xpatience topic^ <4> | |
| SEE ALSO | ||
| -------- | ||
| linkgit:git-revert[1] | ||
| linkgit:gitmergeconflicts[7] | ||
|
|
||
| GIT | ||
| --- | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,7 +49,8 @@ a log message from the user describing the changes. Before the operation, | |
| A merge stops if there's a conflict that cannot be resolved | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "D. Ben Knoble" wrote on the Git mailing list (how to reply to this email): Hi Julia,
On Thu, Sep 24, 2026 at 10:46 AM Julia Evans via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Julia Evans <julia@jvns.ca>
>
> All of the info about merge conflicts has been moved to the new guide
> Among the changes made to the common ancestor's version,
> -non-overlapping ones (that is, you changed an area of the file while the
> -other side left that area intact, or vice versa) are incorporated in the
> -final result verbatim. When both sides made changes to the same area,
> -however, Git cannot randomly pick one side over the other, and asks you to
> -resolve it by leaving what both sides did to that area.
> - * Look at the diffs from each branch. `git log --merge -p <path>`
> - will show diffs first for the `HEAD` version and then the
> - `MERGE_HEAD` version.
I think these are both valuable pieces of information we have lost in
the new guide (unless I misremember just having read patch 1 :).
The first explains a bit more about what a conflict *is*. Maybe that's
old-hat nowadays, but I think it could be nice to keep a statement
about why conflicts exist.
The second is a very useful way to get more context to help resolve
conflicts! I have an alias "conflict = log --oneline --graph
--left-right --boundary --merge" for a similar purpose, and I think
the new guide should help folks discover --merge. Often I can get a
better sense of how to resolve conflicts by comparing the original
changes on each side, or I might at least know who to ask about what
to do.
--
D. Ben KnobleThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Julia Evans" wrote on the Git mailing list (how to reply to this email): On Fri, Sep 25, 2026, at 12:36 PM, D. Ben Knoble wrote:
> Hi Julia,
>
> On Thu, Sep 24, 2026 at 10:46 AM Julia Evans via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
>>
>> From: Julia Evans <julia@jvns.ca>
>>
>> All of the info about merge conflicts has been moved to the new guide
>
>> Among the changes made to the common ancestor's version,
>> -non-overlapping ones (that is, you changed an area of the file while the
>> -other side left that area intact, or vice versa) are incorporated in the
>> -final result verbatim. When both sides made changes to the same area,
>> -however, Git cannot randomly pick one side over the other, and asks you to
>> -resolve it by leaving what both sides did to that area.
>
>> - * Look at the diffs from each branch. `git log --merge -p <path>`
>> - will show diffs first for the `HEAD` version and then the
>> - `MERGE_HEAD` version.
>
> I think these are both valuable pieces of information we have lost in
> the new guide (unless I misremember just having read patch 1 :).
>
> The first explains a bit more about what a conflict *is*. Maybe that's
> old-hat nowadays, but I think it could be nice to keep a statement
> about why conflicts exist.
Will think about this!
> The second is a very useful way to get more context to help resolve
> conflicts! I have an alias "conflict = log --oneline --graph
> --left-right --boundary --merge" for a similar purpose, and I think
> the new guide should help folks discover --merge. Often I can get a
> better sense of how to resolve conflicts by comparing the original
> changes on each side, or I might at least know who to ask about what
> to do.
Thanks, I meant to flag this: the reason I deleted it was really
just that I couldn't understand what `git log --merge -p <path>` did
from the documentation and so I removed it until I could figure it out.
I thought that `--merge` meant that it had something to do with merge
commits, but upon further investigation it looks like that's not true, and
that `--merges` is related to merge commits, `--merge` is something
totally different which is relevant any time there's a conflict
My best guess now is that it would make sense to include this
under "Tools to get more context". Maybe something like this:
> `git log --merge -p <filename>` will print out all commits which
> caused the merge conflict for `<filename>`, and the diff
> of how they changed the file.
("which caused the merge conflict for" is a little more vague, but
I'm trying to convey the intent, and hopefully folks can look at
`man git log` if they want to know the specifics)
This does sound really useful.There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Junio C Hamano wrote on the Git mailing list (how to reply to this email): "Julia Evans" <julia@jvns.ca> writes:
> Thanks, I meant to flag this: the reason I deleted it was really
> just that I couldn't understand what `git log --merge -p <path>` did
> from the documentation and so I removed it until I could figure it out.
It looks at the index to figure out which paths we got conflicts on,
and then does "git log -p <those> <conflicted> <paths>". You can
give a pathspec from the command line to further limit the output.
>> `git log --merge -p <filename>` will print out all commits which
>> caused the merge conflict for `<filename>`, and the diff
>> of how they changed the file.
If you _know_ which exact single file you are interested in, there
is not much you gain from the "--merge" option. "--left-right"
option may be a lot more useful there. It let's you see which side
of the merge gave you what changes.There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ben Knoble wrote on the Git mailing list (how to reply to this email): > Le 25 sept. 2026 à 14:19, Junio C Hamano <gitster@pobox.com> a écrit :
>
> "Julia Evans" <julia@jvns.ca> writes:
>
>> Thanks, I meant to flag this: the reason I deleted it was really
>> just that I couldn't understand what `git log --merge -p <path>` did
>> from the documentation and so I removed it until I could figure it out.
>
> It looks at the index to figure out which paths we got conflicts on,
> and then does "git log -p <those> <conflicted> <paths>". You can
> give a pathspec from the command line to further limit the output.
This explanation omits the manual’s “HEAD…<other>” argument
that the merge option implies, which is important for
understanding the option and my alias ;)There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ben Knoble wrote on the Git mailing list (how to reply to this email): > Le 25 sept. 2026 à 12:59, Julia Evans <julia@jvns.ca> a écrit :
>
>
>
>> On Fri, Sep 25, 2026, at 12:36 PM, D. Ben Knoble wrote:
>> Hi Julia,
[snip]
>> The second is a very useful way to get more context to help resolve
>> conflicts! I have an alias "conflict = log --oneline --graph
>> --left-right --boundary --merge" for a similar purpose, and I think
>> the new guide should help folks discover --merge. Often I can get a
>> better sense of how to resolve conflicts by comparing the original
>> changes on each side, or I might at least know who to ask about what
>> to do.
>
> Thanks, I meant to flag this: the reason I deleted it was really
> just that I couldn't understand what `git log --merge -p <path>` did
> from the documentation and so I removed it until I could figure it out.
> I thought that `--merge` meant that it had something to do with merge
> commits, but upon further investigation it looks like that's not true, and
> that `--merges` is related to merge commits, `--merge` is something
> totally different which is relevant any time there's a conflict
>
> My best guess now is that it would make sense to include this
> under "Tools to get more context". Maybe something like this:
>
>> `git log --merge -p <filename>` will print out all commits which
>> caused the merge conflict for `<filename>`, and the diff
>> of how they changed the file.
>
> ("which caused the merge conflict for" is a little more vague, but
> I'm trying to convey the intent, and hopefully folks can look at
> `man git log` if they want to know the specifics)
>
> This does sound really useful.
That reads well enough for me! Thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Junio C Hamano wrote on the Git mailing list (how to reply to this email): Ben Knoble <ben.knoble@gmail.com> writes:
>> Le 25 sept. 2026 à 14:19, Junio C Hamano <gitster@pobox.com> a écrit :
>>
>> "Julia Evans" <julia@jvns.ca> writes:
>>
>>> Thanks, I meant to flag this: the reason I deleted it was really
>>> just that I couldn't understand what `git log --merge -p <path>` did
>>> from the documentation and so I removed it until I could figure it out.
>>
>> It looks at the index to figure out which paths we got conflicts on,
>> and then does "git log -p <those> <conflicted> <paths>". You can
>> give a pathspec from the command line to further limit the output.
>
> This explanation omits the manual’s “HEAD…<other>” argument
> that the merge option implies, which is important for
> understanding the option and my alias ;)
Ahh, yes, you're right. HEAD...MERGE_HEAD is the more important
half of what --merge gives us that I failed to mention.
And without the symmetric difference traversal it gives,
--left-right would of course not work, either. |
||
| automatically or if `--no-commit` was provided when initiating the | ||
| merge. At that point you can run `git merge --abort` or `git merge | ||
| --continue`. | ||
| --continue`. See linkgit:gitmergeconflicts[7] | ||
| (or `git help mergeconflicts`) for a guide to handling merge conflicts. | ||
|
|
||
| `git merge --abort` will abort the merge process and try to reconstruct | ||
| the pre-merge state. However, if there were uncommitted changes when the | ||
|
|
@@ -231,127 +232,6 @@ git merge v1.2.3^0 | |
| git merge --ff-only v1.2.3 | ||
| ---- | ||
|
|
||
| HOW CONFLICTS ARE PRESENTED | ||
| --------------------------- | ||
|
|
||
| During a merge, the working tree files are updated to reflect the result | ||
| of the merge. Among the changes made to the common ancestor's version, | ||
| non-overlapping ones (that is, you changed an area of the file while the | ||
| other side left that area intact, or vice versa) are incorporated in the | ||
| final result verbatim. When both sides made changes to the same area, | ||
| however, Git cannot randomly pick one side over the other, and asks you to | ||
| resolve it by leaving what both sides did to that area. | ||
|
|
||
| By default, Git uses the same style as the one used by the "merge" program | ||
| from the RCS suite to present such a conflicted hunk, like this: | ||
|
|
||
| ------------ | ||
| Here are lines that are either unchanged from the common | ||
| ancestor, or cleanly resolved because only one side changed, | ||
| or cleanly resolved because both sides changed the same way. | ||
| <<<<<<< yours:sample.txt | ||
| Conflict resolution is hard; | ||
| let's go shopping. | ||
| ======= | ||
| Git makes conflict resolution easy. | ||
| >>>>>>> theirs:sample.txt | ||
| And here is another line that is cleanly resolved or unmodified. | ||
| ------------ | ||
|
|
||
| The area where a pair of conflicting changes happened is marked with markers | ||
| +<<<<<<<+, `=======`, and +>>>>>>>+. The part before the `=======` | ||
| is typically your side, and the part afterwards is typically their side. | ||
|
|
||
| The default format does not show what the original said in the conflicting | ||
| area. You cannot tell how many lines are deleted and replaced with | ||
| Barbie's remark on your side. The only thing you can tell is that your | ||
| side wants to say it is hard and you'd prefer to go shopping, while the | ||
| other side wants to claim it is easy. | ||
|
|
||
| An alternative style can be used by setting the `merge.conflictStyle` | ||
| configuration variable to either `diff3` or `zdiff3`. In `diff3` | ||
| style, the above conflict may look like this: | ||
|
|
||
| ------------ | ||
| Here are lines that are either unchanged from the common | ||
| ancestor, or cleanly resolved because only one side changed, | ||
| <<<<<<< yours:sample.txt | ||
| or cleanly resolved because both sides changed the same way. | ||
| Conflict resolution is hard; | ||
| let's go shopping. | ||
| ||||||| base:sample.txt | ||
| or cleanly resolved because both sides changed identically. | ||
| Conflict resolution is hard. | ||
| ======= | ||
| or cleanly resolved because both sides changed the same way. | ||
| Git makes conflict resolution easy. | ||
| >>>>>>> theirs:sample.txt | ||
| And here is another line that is cleanly resolved or unmodified. | ||
| ------------ | ||
|
|
||
| while in `zdiff3` style, it may look like this: | ||
|
|
||
| ------------ | ||
| Here are lines that are either unchanged from the common | ||
| ancestor, or cleanly resolved because only one side changed, | ||
| or cleanly resolved because both sides changed the same way. | ||
| <<<<<<< yours:sample.txt | ||
| Conflict resolution is hard; | ||
| let's go shopping. | ||
| ||||||| base:sample.txt | ||
| or cleanly resolved because both sides changed identically. | ||
| Conflict resolution is hard. | ||
| ======= | ||
| Git makes conflict resolution easy. | ||
| >>>>>>> theirs:sample.txt | ||
| And here is another line that is cleanly resolved or unmodified. | ||
| ------------ | ||
|
|
||
| In addition to the +<<<<<<<+, `=======`, and +>>>>>>>+ markers, it uses | ||
| another +|||||||+ marker that is followed by the original text. You can | ||
| tell that the original just stated a fact, and your side simply gave in to | ||
| that statement and gave up, while the other side tried to have a more | ||
| positive attitude. You can sometimes come up with a better resolution by | ||
| viewing the original. | ||
|
|
||
|
|
||
| HOW TO RESOLVE CONFLICTS | ||
| ------------------------ | ||
|
|
||
| After seeing a conflict, you can do two things: | ||
|
|
||
| * Decide not to merge. The only clean-ups you need are to reset | ||
| the index file to the `HEAD` commit to reverse 2. and to clean | ||
| up working tree changes made by 2. and 3.; `git merge --abort` | ||
| can be used for this. | ||
|
|
||
| * Resolve the conflicts. Git will mark the conflicts in | ||
| the working tree. Edit the files into shape and | ||
| `git add` them to the index. Use `git commit` or | ||
| `git merge --continue` to seal the deal. The latter command | ||
| checks whether there is a (interrupted) merge in progress | ||
| before calling `git commit`. | ||
|
|
||
| You can work through the conflict with a number of tools: | ||
|
|
||
| * Use a mergetool. `git mergetool` to launch a graphical | ||
| mergetool which will work through the merge with you. | ||
|
|
||
| * Look at the diffs. `git diff` will show a three-way diff, | ||
| highlighting changes from both the `HEAD` and `MERGE_HEAD` | ||
| versions. `git diff AUTO_MERGE` will show what changes you've | ||
| made so far to resolve textual conflicts. | ||
|
|
||
| * Look at the diffs from each branch. `git log --merge -p <path>` | ||
| will show diffs first for the `HEAD` version and then the | ||
| `MERGE_HEAD` version. | ||
|
|
||
| * Look at the originals. `git show :1:filename` shows the | ||
| common ancestor, `git show :2:filename` shows the `HEAD` | ||
| version, and `git show :3:filename` shows the `MERGE_HEAD` | ||
| version. | ||
|
|
||
|
|
||
| EXAMPLES | ||
| -------- | ||
|
|
||
|
|
@@ -406,6 +286,7 @@ linkgit:git-reset[1], | |
| linkgit:git-diff[1], linkgit:git-ls-files[1], | ||
| linkgit:git-add[1], linkgit:git-rm[1], | ||
| linkgit:git-mergetool[1] | ||
| linkgit:gitmergeconflicts[7] | ||
|
|
||
| GIT | ||
| --- | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Junio C Hamano wrote on the Git mailing list (how to reply to this email):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Junio C Hamano wrote on the Git mailing list (how to reply to this email):