From: Junio C Hamano <hidden> Date: 2016-06-15 22:42:13
linux@horizon.com writes:
quoted
+-0 -1 -2::
+ When an unmerged entry is seen, diff against the base version,
+ the "first branch" or the "second branch" respectively.
+
+ The default is to diff against the first branch.
+
Er... why are these flags zero-based?
Because -1 means "first branch" (usually "ours", aka HEAD), and
-2 means "second branch" ("theirs", aka MERGE_HEAD), and -0 is
for the base (aka merge base)?
But I think you are right. The numeric parameters should match
stage number for consistency.
How about if I redo the patch to make diff-files accept -1/-2/-3
instead, and in addition accept "--base", "--ours", and
"--theirs" as synonyms?
Side note. diff3 says MINE OLDER YOURS and the way to remember
the order is they are alphabetical. We can say the same for
base, ours and theirs.
I'm working my way through a thorough understanding of merging.
First I got git-read-tree's 3-way merge down to 6 conditionals, where
a missing entry is considered equal to a missing entry, and a missing
index entry is considered clean.
a) If stage2 == stage3, use stage2
b) If stage1 == stage3, use stage2
c) If the index entry exists and is dirty (working dir changes), FAIL
d) If stage1 == stage2, use stage3
e) If trivial-only, FAIL
f) Return unmerged result for 3-way resolution by git-merge-index.
Case c is needed so you don't change the world out from under
your working directory changes. You could move it earlier and
make things strictire, but that's the minimal restriction.
Then I started thinking about 2-way merge, and how that differed
from a 3-way merge where stage2 was the previous index contents.
If you apply the same rules (with trivial-only true), the only differences
to the big 22-case table in the git-read-tree docs are:
3) This says that if stage1 and state3 exist, use stage3.
3-way says if they're equal, delete the file, while if they're
unequal, it's fail.
If 3-way git-merge-index were allowed, then the conditions that would
change to do it are cases 8 and 12.
The full list of cases and the conditional that applies, is:
0) a
1) d
2) a
3) see above. It's b or e by my logic, but d by the table.
4) b
5) b
6) a
7) a
8) e
9) c
10) d
11) c
12) e
13) c
14) a or b
15) a or b
16) e
17) c
18) a
19) a
20) d
21) c
Given that it all matches up so nicely, I'd like to honestly ask if
case 3 of the conditions is correct. I'd think that if I deleted
a file form te index, and the file wasn't changed on the head I'm
tracking, the right resolution is to keep it deleted. Why override
my deletion?
Sorry if this is a dumb question, but it's not obvious to me.
From: Daniel Barkalow <hidden> Date: 2016-06-15 22:42:14
On Wed, 30 Nov 2005, linux@horizon.com wrote:
Given that it all matches up so nicely, I'd like to honestly ask if
case 3 of the conditions is correct. I'd think that if I deleted
a file form te index, and the file wasn't changed on the head I'm
tracking, the right resolution is to keep it deleted. Why override
my deletion?
You're allowed to do the two-way merge with your index empty, and this
means that you just hadn't read the ancestor, not that you want to remove
everything. I'm not sure what this is useful for.
You're definitely allowed to do a three-way merge with your index empty,
meaning that you don't have any local changes at all, which lets you do a
merge in a temporary index that didn't exist before. (The two-way case is
less interesting, because it's the same as just reading the new tree.)
-Daniel
*This .sig left intentionally blank*
From: Junio C Hamano <hidden> Date: 2016-06-15 22:42:14
linux@horizon.com writes:
3) This says that if stage1 and state3 exist, use stage3.
3-way says if they're equal, delete the file, while if they're
unequal, it's fail.
Given that it all matches up so nicely, I'd like to honestly ask if
case 3 of the conditions is correct. I'd think that if I deleted
a file form te index, and the file wasn't changed on the head I'm
tracking, the right resolution is to keep it deleted. Why override
my deletion?
Sorry if this is a dumb question, but it's not obvious to me.
Funny that I asked exactly the same question when it was done
first:
http://marc.theaimsgroup.com/?l=git&m=111804744926989
It was a question about then-current code, so other cases might
have been changed/corrected/enhanced since then, but I believe
the behaviour for the case in question here stays the same til
this day, and the response from Linus to that article still
applies.
http://marc.theaimsgroup.com/?l=git&m=111807024201485
I'll quote only the punch line here, but the whole thing is
worth a read if you want to understand how this evolved and
what the design choices and decisions were:
Right. We didn't lose anything hugely important.
In theory this could be a delete that we've missed, and we could add a
flag to actually reject this case. However, it's always easy to "recover"
deletes (just delete it again ;), so the loss of information is absolutely
minimal, and it allows starting from an empty index file.
I was playing with the implications of the "deleted file in the
index is not a conflict" merge rule, and came up with the following
octopus test which fails to work. Note line 2 when choosing a
directory to run it in!
#!/bin/bash -xe
rm -rf .git
git-init-db
echo "File A" > a
echo "File B" > b
echo "File C" > c
git-add a b c
git-commit -a -m "Octopus test repository"
git-checkout -b a
echo "Modifications to a" >> a
git-commit -a -m "Modified file a"
git-checkout -b b master
echo "Modifications to b" >> b
git-commit -a -m "Modified file b"
git-checkout -b c master
rm c
git-commit -a -m "Deleted file c"
git-checkout master
#git merge --no-commit "" master c b a
#git merge --no-commit "" master a b c
git-rev-parse a b c > .git/FETCH_HEAD
git-octopus
(Commented out are the first few things I tried.)
Can someone tell me why this doesn't work? It should be a simple
in-index merge.
Right after the incomplete merge (I hacked this into the
git-octopus script), git-ls-files -s produces
100644 8fb437b77759c7709c122fbc8ba43f720e1fbc0a 0 a
100644 b3418f25da4393974aa205e2863f012e5b503369 0 b
100644 df78d3d51c369e1d2f1eadb73464aadd931d56b4 1 c
100644 df78d3d51c369e1d2f1eadb73464aadd931d56b4 2 c
Which should be case 10 of the t/t1000-read-tree-m-3way.sh
table and succeed.
Other things I've discovered...
1) The MAJOR difference between "git checkout" and "git reset --hard"
are that git-checkout takes a *head* as an argument and changes the
.git/HEAD *symlink* to point to that head (ln -sf refs/heads/<head>
.git/HEAD). "git reset" takes a *commit* (<rev>) as an argument and
changes the head that .git/HEAD points to to have that commit as its
hew tip (git-rev-parse <rev> > .git/HEAD)
All the other behavioural differences are relatively minor, and
appropriate for this big difference.
2) Don't use "git branch" to create branches, unless you really
*don't* want to switch to them. Use "git checkout -b".
3) Dumb question: why does "git-commit-tree" need "-p" before the
parent commit arguments? Isn't just argv[2]..argv[argc-1]
good enough?
4) If the "git-read-tree" docs for "--reset", does "ignored" mean
"not overwritten" or "overwritten"?
5) The final "error" message on "git-merge --no-commit" is a bit
alarming for a newbie who uses it because they don't quite trust
git's enough to enable auto-commit. And it should be changed
from ""Automatic merge failed/prevented; fix up by hand" to
"fix up and commit by hand".
Or how about:
"Automatic commit prevented; edit and commit by hand."
which actually tells the truth.
6) The "pickaxe" options are being a bit confusing, and the fact they're
only documented in cvs-migration.txt doesn't help.
7) The git-tag man page could use a little better description of -a.
Yes. The reason is git-read-tree's behaviour was changed
underneath while octopus was looking elsewhere ;-). See
Documentation/technical/trivial-merge.txt, last couple of
lines.
There are two schools of thoughts about "both sides remove"
(case #10) case.
Um, I'm looking at the one-side remove case, which t/t1000 calls
O A B result index requirements
-------------------------------------------------------------------
10 exists O==A missing remove ditto
------------------------------------------------------------------
while trivial-merge.txt says is:
case ancest head remote result
----------------------------------------
10 ancest^ ancest (empty) no merge
I assumed the test case was probably more accurate, given that it's coupled
to code which actually verifies the behaviour.
Some people argued that "the branches might
have renamed that path to different paths and might indicate a
rename/rename conflict" (meaning read-tree should not consider
it trivial, and leave that to upper level "policy layer" to
decide). merge-one-file policy simply says "no, they both
wanted to remove them". If I recall correctly, read-tree itself
merged this case before multi-base rewrite happened (if you are
curious, run 'git whatchanged -p read-tree.c' and look for
"Rewrite read-tree").
Aren't you talking about case #6?
O A B result index requirements
-------------------------------------------------------------------
6 exists missing missing remove must not exist.
------------------------------------------------------------------
case ancest head remote result
----------------------------------------
6 ancest+ (empty) (empty) no merge
quoted
1) The MAJOR difference between "git checkout" and "git reset --hard"
True. "git reset --hard" should be used without <rev> by
novices and with <rev> after they understand what they are
doing (it is used for rewinding/warping heads).
For the longest time I had been under the delusion that
"git-checkout <branch> *" and "git-reset --hard <branch>"
were very similar operations (modulo your comments about
deleting files): overwrite the index and working directory
files with the versions from that branch.
It's hard to say how much I managed to confuse myself by
damaging test repositories while I didn't understand what was
going on.
quoted
2) Don't use "git branch" to create branches, unless you really
*don't* want to switch to them. Use "git checkout -b".
Because...? "git branch foo && git checkout foo" may be
suboptimal to type, but it is not _wrong_; it does not do
anything bad or incorrect.
Yes, I know it works. I suggest avoiding it because there's a much
more convenient alternative and I kept forgetting the second half and
checking my changes in to the wrong branch.
quoted
3) Dumb question: why does "git-commit-tree" need "-p" before the
parent commit arguments? Isn't just argv[2]..argv[argc-1]
good enough?
1. Why not?
3. It does not matter; nobody types that command by hand.
Because it's a real pain to get it properly quoted and set up
in a shell script. "$@" is a lot simpler and easier, and
old /bin/sh only has the one array which provides that magic
quoting behaviour.
(Admittedly, you usually pass the arguments through git-rev-parse
first, and are then guaranteed no embedded whitespace.)
4. It allows us to later add some other flags to commit-tree
(none planned currently).
Making it disappear wouldn't preclude having more options, either,
any more than the variable number of arguments to cp(1) or mv(1)...
quoted
4) If the "git-read-tree" docs for "--reset", does "ignored" mean
"not overwritten" or "overwritten"?
That sentence is very poorly written; a better paraphrasing is
appreciated.
@@ -31,8 +31,8 @@ OPTIONS Perform a merge, not just a read. --reset::-- Same as -m except that unmerged entries will be silently ignored.+ Same as -m except that unmerged entries will be silently overwritten+ (instead of failing). -u:: After a successful merge, update the files in the work
@@ -47,7 +47,6 @@ OPTIONS trees that are not directly related to the current working tree status into a temporary index file.- <tree-ish#>:: The id of the tree object(s) to be read/merged.
quoted
5) The final "error" message on "git-merge --no-commit" is a bit
alarming for a newbie who uses it...
First of all, --no-commit is not meant to be used by newbies,
but you are right.
Well, I can tell you that it's very very attractive to newbies.
The first 5 or 10 times I tried git-merge, I used --no-commit.
(My surprise was mostly that there wasn't a one-letter -x form.)
"Do something really complicated and then commit it to the repository"
is a frightening concept. "Do something really complicated and
then stop and wait for you to see if it was what you expected" is
a lot more comforting.
quoted
6) The "pickaxe" options are being a bit confusing, and the fact they're
only documented in cvs-migration.txt doesn't help.
Docs of git-diff-* family have OPTIONS section, at the end of
which refers you to the diffcore documentation. Suggestions to
a better organization and a patch is appropriate here.
That's a bigger job; I'll work on it when I've finished the docs I'm
writing right. :-)
quoted
7) The git-tag man page could use a little better description of -a.
Please. It should have the same "OPTIONS" section as others do.
I know NOTHING about asciidoc, and really wish I could fix its
lack-of-line-break problem:
GIT-BISECT(1) GIT-BISECT(1)
NAME
git-bisect - Find the change that introduced a bug
SYNOPSIS
git bisect start git bisect bad <rev> git bisect good <rev> git bisect
reset [<branch>] git bisect visualize git bisect replay <logfile> git
bisect log
but emulating what I saw elsewhere...
@@ -10,6 +10,26 @@ SYNOPSIS -------- 'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]+OPTIONS+-------+-a::+ Make an unsigned (anotation) tag object++-s::+ Make a GPG-signed tag, using the default e-mail address's key++-u <key-id>::+ Make a GPG-signed tag, using the given key++-f::+ Replace an existing tag with the given name (instead of failing)++-d::+ Delete an existing tag with the given name++-m <msg>::+ Use the given tag message (instead of prompting)+ DESCRIPTION ----------- Adds a 'tag' reference in .git/refs/tags/
@@ -23,7 +43,7 @@ creates a 'tag' object, and requires the in the tag message. Otherwise just the SHA1 object name of the commit object is-written (i.e. an lightweight tag).+written (i.e. a lightweight tag). A GnuPG signed tag object will be created when `-s` or `-u <key-id>` is used. When `-u <key-id>` is not used, the
From: Junio C Hamano <hidden> Date: 2016-06-15 22:42:14
linux@horizon.com writes:
Um, I'm looking at the one-side remove case, which t/t1000 calls
O A B result index requirements
-------------------------------------------------------------------
10 exists O==A missing remove ditto
------------------------------------------------------------------
while trivial-merge.txt says is:
case ancest head remote result
----------------------------------------
10 ancest^ ancest (empty) no merge
I assumed the test case was probably more accurate, given that it's coupled
to code which actually verifies the behaviour.
You are right. And the test expects something different from
that table in t/t1000 test. Relevant are the lines for ND (one
side No action the other Delete) in the "expected" file. The
test expects the result to be unmerged.
Interesting is that it did so from the day one [*1*]. The very
original read-tree 3-way was quite conservative and left more
things unmerged for the policy script to handle, and it is not
surprising it started like this, but during the course of the
project I thought read-tree was made to collapse more cases in
index. I am a bit surprised we did not loosen it ever since
[*2*]. Thanks for pointing out the discrepancy.
We earlier agreed that the table in t/t1000 test should go and
superseded by trivial-merge.txt, so what the table says right
now is a non-issue, but we _might_ want to revisit the issue of
what should happen in case #8 and #10 sometime in the future, as
the last three lines of trivial-merge.txt mentions. I'd say we
should leave things as they are for now, though.
--reset::
-
- Same as -m except that unmerged entries will be silently ignored.
+ Same as -m except that unmerged entries will be silently overwritten
+ (instead of failing).
Thanks.
"Do something really complicated and then commit it to the repository"
is a frightening concept. "Do something really complicated and
then stop and wait for you to see if it was what you expected" is
a lot more comforting.
Fair enough.
quoted
quoted
7) The git-tag man page could use a little better description of -a.
quoted
Please. It should have the same "OPTIONS" section as others do.
I know NOTHING about asciidoc, and really wish I could fix its
lack-of-line-break problem:
Thanks for pointing that one ont. I think Josef recently did
similar linebreak on git-mv page. I'll try and see if I can
mimic what he did [*3*].
Thanks; applied.
[Footnotes]
*1* A pickaxe example:
$ git whatchanged -p -S'100644 1 ND
100644 2 ND'
shows only two commits. One is the first version of the test,
and the other is to adjust for the output format from
*2* Further archaeology revealed that I did loosening primarily
for the 2-way side, and did not touch much about 3-way merge
other than what used to be marked with ALT. There was no 10ALT
ever so it shows that my memory is simply faulty ;-).
*3* I did that, and it renders HTML side nicer, but it breaks
manpages X-<. Inputs from asciidoc gurus are appreciated.
We earlier agreed that the table in t/t1000 test should go and
superseded by trivial-merge.txt, so what the table says right
now is a non-issue, but we _might_ want to revisit the issue of
what should happen in case #8 and #10 sometime in the future, as
the last three lines of trivial-merge.txt mentions. I'd say we
should leave things as they are for now, though.
But back to my original problem... I don't much care whether it's
done as a trivial merge or a non-trivial merge, but why the #%@#$ can't
it be done as an automatic merge?
As I said, I'm trying to build (and write down) a mental model, so the
behaviour of git can be predicted. My mental model says this should
work. It doesn't. Therefore my mental model is incorrect, and I
don't actually understand what it's doing.
#!/bin/bash -xe
rm -rf .git
git-init-db
echo "File A" > a
echo "File B" > b
echo "File C" > c
git-add a b c
git-commit -a -m "Octopus test repository"
git-checkout -b a
echo "Modifications to a" >> a
git-commit -a -m "Modified file a"
git-checkout -b b master
echo "Modifications to b" >> b
git-commit -a -m "Modified file b"
git-checkout -b c master
rm c
git-commit -a -m "Deleted file c"
git-checkout master
git merge "Merge a, b, c" master a b c
produces...
+ git merge 'Merge a, b, c' master a b c
Trying simple merge with a
Trying simple merge with b
Trying simple merge with c
Simple merge did not work, trying automatic merge.
Removing c
fatal: merge program failed
No merge strategy handled the merge.
*3* I did that, and it renders HTML side nicer, but it breaks
manpages X-<. Inputs from asciidoc gurus are appreciated.
I tried adding " +" at end-of-line, which is supposed to force a
line break, but that didn't have any effect.
Just thinking about the difference between 2-way and 3-way merge...
*Mostly* a 2-way merge is just a 3-way merge where one of the ways
is taken from the index rather than from a tree. But there
are some subtle differences.
This diffierence is what forces octopus merge to form intermediate tree
objects when doing its merges. If there was a way to merge directly
into the index, octopus merge wouldn't have to make intermediate tree
objects that would have to be garbage-collected later.
(Indeed, I originally assumed that Octopus did all its merges in the
index; it's only when I traced the code that I saw it calls git-write-tree
multiple times.)
Is the time saved, and space not wasted, worth implementing a 2-way merge
that more exactly matches 3-way? It should be fairly straightforward
to share the actual merging code.
Opinions solicited.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:42:14
<linux <at> horizon.com> writes:
+ git merge 'Merge a, b, c' master a b c
Trying simple merge with a
Trying simple merge with b
Trying simple merge with c
Simple merge did not work, trying automatic merge.
Removing c
fatal: merge program failed
No merge strategy handled the merge.
I think this is the same problem I fixed yesterday after the breakage report
from Luben Tuikov. You need the ce3ca275452cf069eb6451d6f5b0f424a6f046aa commit.
Sorry about that.
Could you try the latest and see if it still breaks?
produces...
+ git merge 'Merge a, b, c' master a b c
Trying simple merge with a
Trying simple merge with b
Trying simple merge with c
Simple merge did not work, trying automatic merge.
Removing c
fatal: merge program failed
No merge strategy handled the merge.
I'm getting
...
+ git merge 'Merge a, b, c' master a b c
Trying simple merge with a
Trying simple merge with b
Trying simple merge with c
Simple merge did not work, trying automatic merge.
Removing c
Merge 9ca217790c7e6581fe0b8b3b4baf026d03584c66, made by octopus.
a | 1 +
b | 1 +
c | 1 -
3 files changed, 2 insertions(+), 1 deletions(-)
delete mode 100644 c
and I don't see why you wouldn't get that too.
Do you have that broken version of git that had problems with "rmdir" and
thought the unlink failed?
Linus
and I don't see why you wouldn't get that too.
Do you have that broken version of git that had problems with "rmdir" and
thought the unlink failed?
Quite possibly; my previous version of git was 27 November.
(I've been using the Debian package builder, which insists on a
full rebuild each time and is thus annoyingly slow... especially
the "xmlto man" part. I think I'll switch to "make; make install")
Anyway, updated and it works as expected. Sorry for the spurious
complaint.