Re: [RFH] diff -B -M

2015-02-06 Thread Junio C Hamano
Junio C Hamano gits...@pobox.com writes:

 5. Third twist: rewriting by copying
 ...
 One possible way to fix this is to include another patch in the same
 patchset that shows the deletion of major-11.txt.  The rule 2. would
 be further revised to something like:

  rule 2. a patch renaming file A to file B requires that file A
  exists and file B does not exist in the target tree, unless
  another patch in the patchset renames file B to some other
  file (possibly but not necessarily file A) or removed file

Typofix: s/removed/removes/

  B, in which case file B must appear in the target tree.

 Such a patchset would look like this:

 diff --git a/major-08.txt b/major-11.txt
 similarity index 97%
 rename from major-08.txt
 rename to major-11.txt
 ...
 diff --git a/major-11.txt b/major-11.txt
 deleted file mode 100644
 ...

 And these patches, under the re-revised rule 2. and rule 4., would
 apply cleanly to the old tree.

 What about the reverse application?  It would be a patchset that
 creates major-11.txt from nothingness, and creates major-08.txt by
 renaming major-11.txt and editing.  Is the rule 2. re-revised above
 sufficient?

 renaming major-11.txt to major-08.txt requires that major-08.txt
 does not exist in the target tree, unless...

 and the new tree (which is the target of the reverse application)
 only has major-11.txt and not major-08.txt, so this rename should go
 through.  The reverse of the deletion of major-11.txt is a creation
 of it with the contents fully given as the pre-image of the
 (original) patch before reversing it, so that should also be OK with
 rule 3.

... But rule 3. needs tweaking.  The second patch would be creating
major-11.txt which requires major-11.txt to be missing in the target
tree.  But obviously, the new tree the patch we are applying in
reverse was taken from has major-11.txt.  So we would need a
revision to it as well.

 rule 3. a patch that creates file A requires that file A does not exist
 in the target tree, unless another patch in the same patchset
 renames file A away or removes it.

 So tentatively, I would say...

   Action item: do not filter delete-half of the broken pair
   out, even when the other create-half of the pair no longer
   is in the output.

   Action item: update git apply to honor the rule 2.
   re-revised above.

The latter should read:

update git apply to honor the revised rule 2. and 3.

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[RFH] diff -B -M

2015-02-06 Thread Junio C Hamano
I've been thinking about diff -B -M for quite a while, and I am
finding a few interesting problems we have in our codebase.  Here is
a snapshot, with a few action items.

In this write-up of my current thinking, I'll use these terms:

patchset::
Output from a single git diff invocation, which may contain
one or more patch.

patch::
Part of a patchset from a line that begins with diff --git
up to (but excluding) the next line that begins with diff --git.

tree::
diff compares two collections of files; each collection is a
tree.  Left and right sides of the comparison are called old
tree and new tree, respectively.  The tree we attempt to
apply a patchset is the target tree.  The tree we would get
after successful application of a patchset is the resulting
tree.  A tree does not have to be a tree object--we may be
comparing the index and the files in the working tree, for
example.

preimage::
postimage::
Lines in a patch that are prefixed by - or   but not +
that denote what the patched file ought to have for the patchset
to apply (preimage).  Lines with + or   denote what the
patch result ought to look like (postimage).


1. Basics

First the basics.  Let's think about a patchset with a single patch.
What does this patchset tell us?

diff --git a/major-08.txt b/major-08.txt
index 680c5f6..5de90cb 100644
--- a/major-08.txt
+++ b/major-08.txt
@@ -1,3 +1,3 @@
-8. Fortitude.
+8. Strength.

 This is one of the cardinal virtues, of which I shall speak later.

It obviously tells us that the new tree changed Fortitude, that
used to be in the old tree, to Strength, but it actually tells us
a bit more about the old tree.  For this patch to apply, the target
tree must have a file named major-08.txt that begins with lines we
see as the preimage in the patch.


2. Renaming a file

Now let's get a bit fancier and study a patchset with a rename
patch, which I invented very early in the Git's life (it was done
while Linus was still running the project).

What does this patchset tell us?

diff --git rws/major-08.txt marseille/major-11.txt
similarity index 97%
rename from major-08.txt
rename to major-11.txt
index 680c5f6..2ab22a0 100644
--- rws/major-08.txt
+++ marseille/major-11.txt
@@ -1,3 +1,3 @@
-8. Fortitude.
+11. Fortitude.

 This is one of the cardinal virtues, of which I shall speak later.

We can see that this is going from the same old tree as the previous
one's old tree, renames major-08.txt to major-11.txt with slight
modification.  It tells us a lot more about the trees, compared to
the previous example.  For this patchset to apply, the target tree
must satisfy the same preconditon as the previous one about
major-08.txt, and in addition it must lack major-11.txt;
otherwise we wouldn't be renaming a new file to it.  Also, it tells
us that the resulting tree must lack major-08.txt.

So far, these are straight-forward.

In summary:

 rule 1. a patch from file A to file A means file A exists in the
 target tree with contents that match the preimage of the
 patch.  file A will be in the resulting tree.

 rule 2. a patch renaming file A to file B requires that file A
 exists the target tree with contents that match the
 preimage of the patch, and file B does not exist in the
 target tree. file A will not exist in the resulting tree.

 rule 3. a patch that creates file A requires that file A does not exist
 in the target tree.

 rule 4. a patch that deletes file A requires that file A exists in
 the target tree with contents that match the preimage of
 the patch.

The latter two I didn't illustrate with examples, but they should be
obvious.


3. First twist: cross renaming

Now, here is the first twist.  What does this patchset mean?

diff --git rws/major-11.txt marseille/major-08.txt
similarity index 99%
rename from major-11.txt
rename to major-08.txt
index 517d9f8..44e8d3a 100644
--- rws/major-11.txt
+++ marseille/major-08.txt
@@ -1,3 +1,3 @@
-11. Justice.
+8. La Justice

 That the Tarot, though it is of all reasonable antiquity, is not of
diff --git rws/major-08.txt marseille/major-11.txt
similarity index 97%
rename from major-08.txt
rename to major-11.txt
index 5de90cb..a101d5f 100644
--- rws/major-08.txt
+++ marseille/major-11.txt
@@ -1,3 +1,3 @@
-8. Strength.
+11. La Force

 This is one of the cardinal virtues, of which I shall speak later.

This is a swap patchset, that swaps major-08.txt and major-11.txt
with small edit.  You would have done something like this to prepare
it:

$ mv major-11.txt tmp
$ mv major-08.txt major-11.txt
$ mv tmp major-11.txt
$ edit major-08.txt major-11.txt ;# just a little
$ git commit -m swap major-08.txt major-11.txt
$ git diff -B -M HEAD^

A patch renaming major-11.txt