Re: [PATCH v2 2/4] Documentation: warn prominently against merging with dirty trees

12 messages, 4 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH v2 2/4] Documentation: warn prominently against merging with dirty trees

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:47:59

Jonathan Nieder [off-list ref] writes:
Here is a scenario I worry about:

Suppose I have a change to main.c staged, to add a feature that others
have discussed as well.  After a short distraction, I return and run
‘git pull’ to see what upstream has been working on.
If your index is dirty, any "mergy" operation will refuse to work *before*
touching anything, so you won't use "git reset --merge" to begin with.

You are allowed to have local modifications only in your work tree.
Furthermore, even git experts limit them to something they feel they can
afford to lose and recreate easily if necessary.  See for example:

  http://thread.gmane.org/gmane.comp.version-control.git/15148/focus=15476

That is why I said:

  Of course, the user needs to understand what he or she is doing (see
  http://thread.gmane.org/gmane.comp.version-control.git/136166/focus=136171
  for example).  And that is one reason we (at least I) try to teach new
  people to start working from a clean tree, until they get comfortable
  working with mergy operations.

and that is why the archived article referenced above refers to

  http://gitster.livejournal.com/29060.html

You need to be able to tell the two ways in which a "mergy" operation can
"fail" apart [*1*].

 - One that stops before touching anything (either your index was dirty
   and nothing happened, or your index was clean but you had local
   modifications in your work tree).  You do not run "git reset --merge",
   for this one; and

 - Another that goes ahead and results in conflicts.  When you got these
   conflicts, you can "reset --merge" them away.

[Footnote]

*1* Strictly speaking, the latter is not even a "failure"; it allowed you
to make progress, merging all the auto-mergeable parts without your help,
and only asking you to handle the remainder.

Re: [PATCH v2 2/4] Documentation: warn prominently against merging with dirty trees

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

Junio C Hamano wrote:
Jonathan Nieder [off-list ref] writes:
quoted
Here is a scenario I worry about:

Suppose I have a change to main.c staged, to add a feature that others
have discussed as well.  After a short distraction, I return and run
‘git pull’ to see what upstream has been working on.
If your index is dirty, any "mergy" operation will refuse to work *before*
touching anything, so you won't use "git reset --merge" to begin with.
Yes, that is true.  And I was not worried about that.

As the git-merge manual explains:

| A merge is always between the current HEAD and one or more commits
| (usually, branch head or tag), and the index file must match the tree of
| HEAD commit (i.e. the contents of the last commit) when it starts out. In
| other words, git diff --cached HEAD must report no changes. (One exception
| is when the changed index entries are already in the same state that would
| result from the merge anyway.)

The potentially problematic scenario for "git reset --merge" is this
last one, where a changed index entry is already in the same state
that would result from the merge.  Would a "git reset --merge" reset
the changed contents away?
You are allowed to have local modifications only in your work tree.
Furthermore, even git experts limit them to something they feel they can
afford to lose and recreate easily if necessary.
Sadly, even a small change disappearing can be unnerving for an expert
and dangerous for a novice.
You need to be able to tell the two ways in which a "mergy" operation can
"fail" apart [*1*].
Thanks for bringing this up.  The manual does not emphasize that
point at all, but it should.

Jonathan

[PATCH 0/6] Re: Documentation: warn prominently against merging with dirty trees

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

Jonathan Nieder wrote:
Junio C Hamano wrote:
quoted
You need to be able to tell the two ways in which a "mergy" operation can
"fail" apart [*1*].
Thanks for bringing this up.  The manual does not emphasize that
point at all, but it should.
Maybe something like this (patch 4) could help.  This should pass
through Thomas’s tree to avoid conflicts with his other changes; but
of course, I would be glad to hear any thoughts you have before then.

Jonathan Nieder (6):
  Documentation: clarify one-line description for merge
  Documentation: merge: add an overview
  Documentation: merge: move configuration section to the end
  Documentation: emphasize when git merge terminates early
  Documentation: merge: add a section about fast-forward
  Documentation: merge: tweak HOW MERGE WORKS section

 Documentation/git-merge.txt |  149 ++++++++++++++++++++++++++----------------
 1 files changed, 92 insertions(+), 57 deletions(-)

[PATCH/RFC 1/6] Documentation: clarify one-line description for merge

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

The 'git merge' command is generally not used to tie completely
independent projects together (though it can be used to do that)
but to reconcile branches of development that may have diverged.
Try to make this clearer in its one-line description.

Cc: Petr Baudis <redacted>
Cc: Junio C Hamano <redacted>
Cc: Thomas Rast <redacted>
Signed-off-by: Jonathan Nieder <redacted>
---
I am not sure this is an improvement at all.  Mostly I wanted to
convey the idea of code forks being reconciled, but the resulting
phrase is not nearly as nice.

 Documentation/git-merge.txt |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index e886c2e..394ad0a 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -3,8 +3,7 @@ git-merge(1)
 
 NAME
 ----
-git-merge - Join two or more development histories together
-
+git-merge - Re-join diverging branches of development
 
 SYNOPSIS
 --------
-- 
1.6.6

[PATCH 2/6] Documentation: merge: add an overview

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

The reader unfamiliar with the concepts of branching and merging
would have been completely lost.  Try to help him with a diagram.

The diagram comes from the 'git rebase' manual page.

Cc: Petr Baudis <redacted>
Cc: Junio C Hamano <redacted>
Cc: Thomas Rast <redacted>,
Signed-off-by: Jonathan Nieder <redacted>
---
Does this tell enough of the story?

 Documentation/git-merge.txt |   27 +++++++++++++++++++++++++--
 1 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 394ad0a..fe190e2 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -14,8 +14,31 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This is the top-level interface to the merge machinery
-which drives multiple merge strategy scripts.
+Incorporates changes leading up to the named commits into the
+current branch.  This command is used by 'git pull' to incorporate
+remote changes from another repository and may be used by hand to
+merge changes from one branch into another.
+
+Assume the following history exists and the current branch is
+"`master`":
+
+------------
+          A---B---C topic
+         /
+    D---E---F---G master
+------------
+
+Then "`git merge topic`" will apply the changes from `A`, `B`,
+and `C` to the work tree, and if they do not conflict with any
+changes from `master`, will store the result in a new commit along
+with the names of the two parent commits and a log message from the
+user describing the changes.
+
+------------
+          A---B---C topic
+         /         \
+    D---E---F---G---H master
+------------
 
 The second syntax (<msg> `HEAD` <remote>) is supported for
 historical reasons.  Do not use it from the command line or in
-- 
1.6.6

[PATCH 4/6] Documentation: emphasize when git merge terminates early

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

A merge-based operation in git can fail in two ways:

 - One that stops before touching anything (either your index was
   dirty and nothing happened, or your index was clean but you
   had local modifications in your work tree).

 - Another that goes ahead and results in conflicts.

The 'git merge' manual explains half of the first case as follows:

| A merge is always between the current `HEAD` and one or more
| commits (usually, branch head or tag), and the index file must
| match the tree of `HEAD` commit (i.e. the contents of the last commit)
| when it starts out.

The placement of this sentence makes it easy to skip over, and
its formulation is perhaps too formal to be memorable.

So give this point its own section and expand upon it.  Most of
the added text is taken from <http://gitster.livejournal.com/25801.html>.

Cc: Petr Baudis <redacted>,
Cc: Junio C Hamano <redacted>
Cc: Thomas Rast <redacted>
Not-signed-off-by: Jonathan Nieder [off-list ref]
---
This is not signed off because most of the text is from Junio’s
blog.  I hope that is okay.

 Documentation/git-merge.txt |   34 ++++++++++++++++++++++++----------
 1 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index e29bb97..8950aa4 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -60,6 +60,28 @@ include::merge-options.txt[]
 	least one <remote>.  Specifying more than one <remote>
 	obviously means you are trying an Octopus.
 
+PRE-MERGE CHECKS
+----------------
+
+In some other version control systems, you merge/update and then
+commit, with the risk of clobbering your changes with humongous
+conflicts. You shouldn't be pulling or merging if you haven't got
+your own work into good shape and committed it locally (see also
+linkgit:git-stash[1]).
+
+But novices can make this mistake, and 'git pull' and 'git merge'
+will stop without doing anything when local uncommitted changes
+overlap with files that 'git pull'/'git merge' may need to update.
+
+Also, to avoid unrelated changes in the recorded commit, 'git
+pull' and 'git merge' abort if there are any changes registered
+in the index relative to the contents of the `HEAD` commit.
+(One exception is when the changed index entries are already in
+the same state that would result from the merge anyway.)
+
+If all named commits are already ancestors of `HEAD`, 'git merge'
+will exit early with the message "Already up-to-date."
+
 include::merge-strategies.txt[]
 
 
@@ -70,17 +92,9 @@ HOW MERGE WORKS
 ---------------
 
 A merge is always between the current `HEAD` and one or more
-commits (usually, branch head or tag), and the index file must
-match the tree of `HEAD` commit (i.e. the contents of the last commit)
-when it starts out.  In other words, `git diff --cached HEAD` must
-report no changes.  (One exception is when the changed index
-entries are already in the same state that would result from
-the merge anyway.)
-
-Three kinds of merge can happen:
+commits (usually, branch head or tag).
 
-* The merged commit is already contained in `HEAD`. This is the
-  simplest case, called "Already up-to-date."
+Two kinds of merge can happen:
 
 * `HEAD` is already contained in the merged commit. This is the
   most common case especially when invoked from 'git pull':
-- 
1.6.6

[PATCH 5/6] Documentation: merge: add a section about fast-forward

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

Novices sometimes find the behavior of 'git merge' in the
fast-forward case surprising.  Add a section to the manual to
describe it more thoroughly.

Cc: Petr Baudis <redacted>,
Cc: Junio C Hamano <redacted>
Cc: Thomas Rast <redacted>
Signed-off-by: Jonathan Nieder <redacted>
---
 Documentation/git-merge.txt |   31 ++++++++++++++++++-------------
 1 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 8950aa4..ec9c6d3 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -82,6 +82,20 @@ the same state that would result from the merge anyway.)
 If all named commits are already ancestors of `HEAD`, 'git merge'
 will exit early with the message "Already up-to-date."
 
+FAST-FORWARD MERGE
+------------------
+
+Often the current branch head is an ancestor of the named commit.
+This is the most common case especially when invoked from 'git
+pull': you are tracking an upstream repository, you have committed
+no local changes, and now you want to update to a newer upstream
+revision.  In this case, a new commit is not needed to store the
+combined history; instead, the `HEAD` (along with the index) is
+updated to point at the named commit, without creating an extra
+merge commit.
+
+This behavior can be suppressed with the `--no-ff` option.
+
 include::merge-strategies.txt[]
 
 
@@ -94,19 +108,10 @@ HOW MERGE WORKS
 A merge is always between the current `HEAD` and one or more
 commits (usually, branch head or tag).
 
-Two kinds of merge can happen:
-
-* `HEAD` is already contained in the merged commit. This is the
-  most common case especially when invoked from 'git pull':
-  you are tracking an upstream repository, have committed no local
-  changes and now you want to update to a newer upstream revision.
-  Your `HEAD` (and the index) is updated to point at the merged
-  commit, without creating an extra merge commit.  This is
-  called "Fast-forward".
-
-* Both the merged commit and `HEAD` are independent and must be
-  tied together by a merge commit that has both of them as its parents.
-  The rest of this section describes this "True merge" case.
+Except in a fast-forward merge (see above), the branches to be
+merged must be tied together by a merge commit that has both of them
+as its parents.
+The rest of this section describes this "True merge" case.
 
 The chosen merge strategy merges the two commits into a single
 new source tree.
-- 
1.6.6

[PATCH 6/6] Documentation: tweak How Merge Works

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:47:59

Change heading to TRUE MERGE.  The whole manual page is about how
merges work.

Start to explain what it means to merge two commits into a single
tree.

Do not assume the commits named on the 'git merge' command line
come from another repository.  For simplicity, still assume they
are branch heads for now, though.

Do not give start any list items with `code`; a toolchain bug
makes the resulting nroff look wrong.

Recommend reset --merged for safely cancelling a failed merge.

Cc: Petr Baudis <redacted>
Cc: Junio C Hamano <redacted>
Cc: Thomas Rast <redacted>
Signed-off-by: Jonathan Nieder <redacted>
---
 Documentation/git-merge.txt |   56 +++++++++++++++++++-----------------------
 1 files changed, 25 insertions(+), 31 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index ec9c6d3..7ae0f65 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -96,62 +96,56 @@ merge commit.
 
 This behavior can be suppressed with the `--no-ff` option.
 
-include::merge-strategies.txt[]
-
-
-If you tried a merge which resulted in complex conflicts and
-want to start over, you can recover with 'git-reset'.
-
-HOW MERGE WORKS
----------------
-
-A merge is always between the current `HEAD` and one or more
-commits (usually, branch head or tag).
+TRUE MERGE
+----------
 
 Except in a fast-forward merge (see above), the branches to be
 merged must be tied together by a merge commit that has both of them
 as its parents.
 The rest of this section describes this "True merge" case.
 
-The chosen merge strategy merges the two commits into a single
-new source tree.
 When things merge cleanly, this is what happens:
 
-1. The results are updated both in the index file and in your
-   working tree;
-2. Index file is written out as a tree;
+1. A version reconciling the changes from all branches to be
+   merged is written to the index file and your working tree;
+2. The index file is written out as a tree;
 3. The tree gets committed; and
 4. The `HEAD` pointer gets advanced.
 
 Because of 2., we require that the original state of the index
 file matches exactly the current `HEAD` commit; otherwise we
-will write out your local changes already registered in your
+would write out your local changes already registered in your
 index file along with the merge result, which is not good.
 Because 1. involves only those paths differing between your
-branch and the remote branch you are pulling from during the
-merge (which is typically a fraction of the whole tree), you can
-have local modifications in your working tree as long as they do
-not overlap with what the merge updates.
-
-When there are conflicts, the following happens:
+branch and the other branches (which is typically a fraction of
+the whole tree), you can have local modifications in your
+working tree as long as they do not overlap with what the merge
+updates.
 
-1. `HEAD` stays the same.
+When it is not obvious how to reconcile the changes, the following
+happens:
 
-2. Cleanly merged paths are updated both in the index file and
+1. The `HEAD` pointer stays the same.
+2. The `MERGE_HEAD` ref is set to point to the other branch head.
+3. Paths that merged cleanly are updated both in the index file and
    in your working tree.
-
-3. For conflicting paths, the index file records up to three
+4. For conflicting paths, the index file records up to three
    versions; stage1 stores the version from the common ancestor,
-   stage2 from `HEAD`, and stage3 from the remote branch (you
+   stage2 from `HEAD`, and stage3 from `MERGE_HEAD` (you
    can inspect the stages with `git ls-files -u`).  The working
    tree files contain the result of the "merge" program; i.e. 3-way
-   merge results with familiar conflict markers `<<< === >>>`.
-
-4. No other changes are done.  In particular, the local
+   merge results with familiar conflict markers `<<<` `===` `>>>`.
+5. No other changes are done.  In particular, the local
    modifications you had before you started merge will stay the
    same and the index entries for them stay as they were,
    i.e. matching `HEAD`.
 
+If you tried a merge which resulted in complex conflicts and
+want to start over, you can recover with `git reset --merged`.
+
+include::merge-strategies.txt[]
+
+
 HOW CONFLICTS ARE PRESENTED
 ---------------------------
 
-- 
1.6.6

Re: [PATCH 4/6] Documentation: emphasize when git merge terminates early

From: Thomas Rast <hidden>
Date: 2016-06-15 22:48:00

Jonathan Nieder wrote:
+In some other version control systems, you merge/update and then
+commit, with the risk of clobbering your changes with humongous
+conflicts. You shouldn't be pulling or merging if you haven't got
+your own work into good shape and committed it locally (see also
+linkgit:git-stash[1]).
Isn't it wrong to talk about other VCS, especially when writing down
what Git does *not*?  The user wants to know what git *does*,
otherwise he wouldn't be looking in the manual.
+If all named commits are already ancestors of `HEAD`, 'git merge'
+will exit early with the message "Already up-to-date."
<aside>
I suspect this is little-known but the equivalent message for an
octopus is actually: "Already up-to-date. Yeeah!"
</aside>

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

Re: [PATCH 6/6] Documentation: tweak How Merge Works

From: Thomas Rast <hidden>
Date: 2016-06-15 22:48:00

The below and earlier comments aside, I really like this series.  It
seems to make the manpage much more accessible.

Jonathan Nieder wrote:
quoted hunk
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index ec9c6d3..7ae0f65 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -96,62 +96,56 @@ merge commit.
 
 This behavior can be suppressed with the `--no-ff` option.
 
-include::merge-strategies.txt[]
-
-
I'm not sure whether you deliberately did this, or deliberately
deferred it to this patch, but this "sneak moves" the merge-strategies
section beyond "TRUE MERGE" (was "HOW MERGE WORKS").

So the section layout changes as follows when comparing current master
with your series:

 NAME
 SYNOPSIS
 DESCRIPTION
 OPTIONS
+PRE-MERGE CHECKS
+FAST-FORWARD MERGE
+TRUE MERGE
 MERGE STRATEGIES
-CONFIGURATION
-HOW MERGE WORKS
 HOW CONFLICTS ARE PRESENTED
 HOW TO RESOLVE CONFLICTS
 EXAMPLES
+CONFIGURATION
 SEE ALSO
 AUTHOR
 DOCUMENTATION
 GIT
 NOTES

While I agree with the general intent of deferring the strategies
further back, wouldn't it be better go all the way and instead put
them before (or even after, but one of them uses -s ours) "EXAMPLES"?
The average user will care more about conflicts than about strategies
other than 'recursive'.
+1. A version reconciling the changes from all branches to be
+   merged is written to the index file and your working tree;
+2. The index file is written out as a tree;
 3. The tree gets committed; and
 4. The `HEAD` pointer gets advanced.
Could we do away with the detail here?  The user most likely does not
care about the exact order because he cannot "see" it happening
anyway.  So how about

  A merged version reconciling the changes from all branches to be
  merged is committed, and your HEAD, index, and working tree are
  updated to it.  (It is possible to have modifications in the working
  tree as long as they do not overlap; the update will preserve them.)

and then snip everything up to
+When it is not obvious how to reconcile the changes, the following
+happens:
because that is far more important to the user: he is left in the
middle of the described state.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

Re: [PATCH v2 2/4] Documentation: warn prominently against merging with dirty trees

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:48:00

Jonathan Nieder [off-list ref] writes:
| A merge is always between the current HEAD and one or more commits
| (usually, branch head or tag), and the index file must match the tree of
| HEAD commit (i.e. the contents of the last commit) when it starts out. In
| other words, git diff --cached HEAD must report no changes. (One exception
| is when the changed index entries are already in the same state that would
| result from the merge anyway.)

The potentially problematic scenario for "git reset --merge" is this
last one, where a changed index entry is already in the same state
that would result from the merge.  Would a "git reset --merge" reset
the changed contents away?
It will discard the change, the one you independently picked up, but the
change agreed with what was done by the the trash history that you are
cancelling merge with.  You wouldn't miss losing the same change as in
that trash history.

Re: [PATCH 0/6] Re: Documentation: warn prominently against merging with dirty trees

From: Petr Baudis <hidden>
Date: 2016-06-15 22:48:00

On Mon, Jan 11, 2010 at 02:21:23AM -0600, Jonathan Nieder wrote:
Jonathan Nieder (6):
  Documentation: clarify one-line description for merge
I don't think this is an improvement and prefer the original phrasing.
  Documentation: merge: move configuration section to the end
Ack.

I will reply to the other patches in separate mails.

				Petr "Pasky" Baudis
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help