Some thoughts on resolving conflicts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 01 Dec 2006 09:36:00 -0800, Carl Worth wrote:
> To finish off, I'd like to propose descriptions of the commands to
> allow the user to use the "without staging" commands as a complete set
> while being able to easily ignore any of the staging capabilities.
> This does trigger a need for a semantic change in the "add"
> command. Here are the proposed descriptions:

By the way, back when we used to call it the "index" one of the things
that was often mentioned as a reason not to "hide the index" is that
the index ends up being so important during the process of resolving a
merge.

This is extremely true, and this is where git really starts to
shine. I've seen people get really put off by the index when they
first encounter "commit -a" or a messages instructing them to
"update-index" something. But, if people are properly presented with
what git offers for helping with conflict resolution then I think they
will fall in love with it.

But I think "hide the index" vs. "celebrate the index" frames the
debate entirely wrong. It's not a matter of "working tree" vs. "index"
being the king. The king is what the user wants to accomplish and what
does git offer to help with that.

So, for example, in the case of conflict resolution, what git offers
in an iterative process involving:

	git diff	Shows what still needs to be resolved

	git resolve	Indicate to git that conflicts are resolved in
			the specified files

(Yes, I'm assuming a future "resolve" synonym for update-index here)
And finally, "git commit" when complete. This is a fantastic sequence
since it fits what the user wants to do and helps the user do it, (and
the incremental nature of it is helpful for large conflicts).

Note that I don't think it's important whether the final "git commit"
executes a "commit -a" or a mode traditional commit-the-index. It
would be exceedingly rare for someone to want to make a partial,
staged commit during conflict resolution. So I think that special case
can be entirely ignored when considering the user-interface.

So git provides tools well suited to the job here. One thing it
doesn't do well is to advertise them to the user. It would probably be
helpful to print some small section of advice and guidance when the
conflict happens. Right now, git spews a lot of scary internal state
that definitely gives the impression of things going wrong, and
doesn't tell the user much about what to do. It would be nice to say
something more along the lines of "A conflict occurred during the
merge attempt. That's nothing to worry about---it happens
sometimes. And here are some tools that git offers to help you fix
things up:..."

And there are other lovely things that git provides, such as:

	git log -p --merge	Shows commits that contributed to this conflict

	git diff --ours		Show changes in working tree compared
				to our latest commit for unresolved files

	git diff --theirs	Show changes in working tree compared
				to the commit being merged in for
				unresolved files

To tell the truth, I hadn't really played with "diff --ours" and "diff
--theirs" much before. They're right handy! I can't find any
documentation for them, (it might exist somewhere deep in the plumbing
documentation but I can't find it). It would be great to have
examples in the "git diff" page showing these off, and maybe some
hints in the message that comes from the conflicted merge.

So the above commands are wildly useful. But there not useful because
"the index is an essential part of git", they're useful because they
help the user get information related to what the user is doing.

One command that I didn't find in my experimentation was how to see
the multi-parent diff after resolving the conflict. I found that I can
do a single-parent thing with:

	git diff --cached	Show changes in staging area compared
				to our latest commit.

But I didn't figure out how to get the multi-parent thing there
yet. After I make the commit object I _can_ see the result I want with
"git show", but it would be nice to be able to see that before the
commit.

Surely there's a command-line option somewhere that does this, with a
name like -cc or -C or something, but it's something that I would
argue should acquire a different name---that is, if I were doing
conflict resolution often. As it stands now, I rarely have any
conflicts to resolve, so any user-interface warts that git has here
haven't rubbed me the wrong way yet. Other than the conflict spew
which gives the impression of "Git tried (multiple ways) and failed to
merge this mess. You're on your own now."

-Carl

PS. Here's the example I just used to experiment with conflict
resolution. It's something like this that would be nice to have in
something like "git tutorial conflict-resolution" which would run the
following sequence of commands for the user and then invite the user
to play with things like "git diff --ours" and "git diff --theirs".

The commands below look really ugly, so we definitely don't want the
tutorial reader to ever have to go through all this
state-creation. But the end result---what the user sees in "git diff"
is so intuitive that it would be wonderful to have this kind of thing
readily available at the command-line.

A more ambitious example might setup conflict in multiple files to
teach the incremental nature of using "git diff" and "git resolve"
together.

mkdir git-tutorial-conflict-resolution
cd git-tutorial-conflict-resolution
git init-db
echo 'vvv Context paragraph 1 vvv
This is a paragraph that exists for context.
It will be unmodified in both branches.
^^^ Context paragraph 1 ^^^

This is a paragraph that I will modify in master
and delete in other.

vvv Context paragraph 2 vvv
This is a second paragraph that exists for context.
It too, will be unmodified in both branches.
^^^ Context paragraph 2 ^^^

This is a paragraph that I will delete in master
and modify in other.

vvv Context paragraph 3 vvv
This is the third paragraph that exists for context.
Again, it will be unmodified in both branches.
^^^ Context paragraph 3 ^^^

This is a paragraph that I will modify in two
different ways in master and other.
' > file
git add file
git commit -m "add file"
git branch other
echo 'vvv Context paragraph 1 vvv
This is a paragraph that exists for context.
It will be unmodified in both branches.
^^^ Context paragraph 1 ^^^

This is a paragraph that I have modified
in master.

vvv Context paragraph 2 vvv
This is a second paragraph that exists for context.
It too, will be unmodified in both branches.
^^^ Context paragraph 2 ^^^

vvv Context paragraph 3 vvv
This is the third paragraph that exists for context.
Again, it will be unmodified in both branches.
^^^ Context paragraph 3 ^^^

This is a paragraph that I have modified
in master.
' > file
git commit -a -m "master modifications"
git checkout other
echo 'vvv Context paragraph 1 vvv
This is a paragraph that exists for context.
It will be unmodified in both branches.
^^^ Context paragraph 1 ^^^

vvv Context paragraph 2 vvv
This is a second paragraph that exists for context.
It too, will be unmodified in both branches.
^^^ Context paragraph 2 ^^^

This is a paragraph that I have modified
in other.

vvv Context paragraph 3 vvv
This is the third paragraph that exists for context.
Again, it will be unmodified in both branches.
^^^ Context paragraph 3 ^^^

This is a paragraph that I have modified
in other
' > file
git commit -a -m "other modifications"
git checkout master
git pull . other

Attachment: pgpaAR50rTCEa.pgp
Description: PGP signature


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]