Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-20 Thread Junio C Hamano
Jeff King  writes:

>  But I think that points to a larger problem, which is that we do
>  not want to just look at the entries that are different between the
>  tree and the index.

True.  The unpack-trees API knows how to walk the index and trees in
parallel, and I tend to agree that it may be a more suitable vehicle
for this purpose.
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-19 Thread Jeff King
On Thu, Sep 19, 2013 at 11:02:17AM -0700, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > An alternative would be to write the new entries to a temporary index
> > in memory. And then you can throw away the entries in the current index
> > that match the pathspec, and add in the entries from the temporary
> > index. I was just hoping that unpack-trees would do all of that for me.
> > :)
> 
> Isn't a "go there" one-way merge with pathspecs very similar to what
> happens in "reset -- pathspec" except for the working tree part?

I thought so at first, but now I'm not so sure...

> suspect that it may be sufficient to mimic the read_from_tree() and
> adapt update_index_from_diff() callback in builtin/reset.c to also
> update the working tree (and we can do so unconditionally without
> checking if we have any local modification in this case, which
> simplifies things a lot), but I may be missing something.

It almost works to simply update the index as "reset" does via
diff_cache, marking each updated entry with CE_UPDATE, and then let the
rest of checkout_paths proceed, which handles updating the working tree
based on the new index.

But I found two problems:

  1. The diff never feeds us entries that are unchanged, so we never
 mark them for update. But that interferes with later code to check
 whether our pathspecs matched anything (so we complain on "git
 reset --hard; git checkout HEAD foo" would barf on the checkout,
 since we do not need to touch foo).

 But I think that points to a larger problem, which is that we do
 not want to just look at the entries that are different between the
 tree and the index. We also need to care about the entries that are
 different in the working tree and index, because those need written
 out, too.

  2. The code in checkout_paths cannot handle the deletion for us,
 because it doesn't even know about the path any more (we removed it
 during the index diff). I think we could get around this by leaving
 an entry with the CE_WT_REMOVE flag set. But it looks like there is
 a bit more magic to removing a path than just remove_or_warn().
 unpack-trees has unlink_entry, which queues up leading directories
 for removal.

I think (2) is a matter of refactoring (but again, if we could convince
unpack-trees to do this for us, that might be the nicest way to reuse
the code). But (1) points to a larger problem in thinking about this as
a "diff"; it is really about re-loading bits of the index, and then
checking it out into the working tree.

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-19 Thread Junio C Hamano
Jeff King  writes:

> An alternative would be to write the new entries to a temporary index
> in memory. And then you can throw away the entries in the current index
> that match the pathspec, and add in the entries from the temporary
> index. I was just hoping that unpack-trees would do all of that for me.
> :)

Isn't a "go there" one-way merge with pathspecs very similar to what
happens in "reset -- pathspec" except for the working tree part?  I
suspect that it may be sufficient to mimic the read_from_tree() and
adapt update_index_from_diff() callback in builtin/reset.c to also
update the working tree (and we can do so unconditionally without
checking if we have any local modification in this case, which
simplifies things a lot), but I may be missing something.



--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-19 Thread Jeff King
On Tue, Sep 17, 2013 at 03:14:39PM -0700, Junio C Hamano wrote:

> Yeah, then I agree that "git checkout HEAD^ -- subdir" should be a
> one-way "go HEAD^" merge limited only to the paths that match
> subdir/.
> 
> If implemented in a straight-forward way, I suspect that we may end
> up not removing subdir/b in Uwe's sample transcript. I am not sure
> if that is a good thing or not, though.  If the index originally
> tracked and then "going to" tree does not, I think removing it would
> match "ignore local modifications" rule, as subdir/a that is tracked
> in the index and also in "going to" tree does get overwritten to
> match the state recorded in the tree.

I had assumed the goal was to subdir/b (by the reasoning above, and the
"rm -rf && tar" analogy you gave earlier).

I tried a very hacky attempt at shoving unpack-trees into the right spot
in checkout_paths. But its pathspec handling from unpack_trees is not
quite what we want.

In Uwe's case, it did delete subdir/b and overwrite subdir/a, which I'd
expect. But if there was an additional file outside of subdir, it got
deleted, too.  The problem is that I was giving the regular index to
unpack_trees as the destination; so it wrote out only the bits of the
index under the pathspec subdir/, and omitted the rest entirely. I had
hoped instead it would leave those parts untouched from the source.

An alternative would be to write the new entries to a temporary index
in memory. And then you can throw away the entries in the current index
that match the pathspec, and add in the entries from the temporary
index. I was just hoping that unpack-trees would do all of that for me.
:)

At this point, I'm giving up for now. I was hoping a naive application
of unpack-trees would just work (and reduce the code size to boot), but
it is obviously a bit more complicated than that. I still think it's a
good idea for checkout to behave as Uwe described, but I don't think
it's that high a priority, and I have other stuff I'd prefer to work on
at the moment.

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Junio C Hamano
Jeff King  writes:

> On Tue, Sep 17, 2013 at 03:00:41PM -0700, Junio C Hamano wrote:
>
>> > So given that, is it fair to say that a one-way "go here" merge, limited
>> > by pathspec, is the closest equivalent?
>> 
>> Sorry, but it is unclear to me what you mean by one-way "go here"
>> merge.  Do you mean oneway_merge() in unpack-trees.c?
>
> Yes, that is what I meant.

Yeah, then I agree that "git checkout HEAD^ -- subdir" should be a
one-way "go HEAD^" merge limited only to the paths that match
subdir/.

If implemented in a straight-forward way, I suspect that we may end
up not removing subdir/b in Uwe's sample transcript. I am not sure
if that is a good thing or not, though.  If the index originally
tracked and then "going to" tree does not, I think removing it would
match "ignore local modifications" rule, as subdir/a that is tracked
in the index and also in "going to" tree does get overwritten to
match the state recorded in the tree.

--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Jeff King
On Tue, Sep 17, 2013 at 03:00:41PM -0700, Junio C Hamano wrote:

> > So given that, is it fair to say that a one-way "go here" merge, limited
> > by pathspec, is the closest equivalent?
> 
> Sorry, but it is unclear to me what you mean by one-way "go here"
> merge.  Do you mean oneway_merge() in unpack-trees.c?

Yes, that is what I meant.

In my mind, oneway_merge is "go here unconditionally", twoway_merge is
"go from A to B, respecting changes already made from A", and
threeway_merge is a "real" merge. But I am not sure if that is accurate
or just my confused mental model of unpack-trees. :)

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Junio C Hamano
Jeff King  writes:

> On Tue, Sep 17, 2013 at 01:40:17PM -0700, Junio C Hamano wrote:
>
>> Taking the state of a subdirectory as a whole as "content", the
>> change we are discussing will make it more like "rm -fr dir && tar
>> xf some-content dir" to replace the directory wholesale, which I
>> personally think is a good thing in the longer term.
>
> Yeah, that makes sense. What about untracked files?

Obviously we cannot literally do "rm -fr dir && tar x", but I agree
that if tree-ish has a path that is not tracked in the current
index, the path should be overwritten and made identical to what is
in the tree-ish.

> Right now we overwrite them if the tree-ish has an entry at the same
> path; that is a bit more dangerous than the rest of git, but does match
> the "ignore local modifications" rule. I assume if we handled deletions,
> though, that we would simply leave them be.
>
> So given that, is it fair to say that a one-way "go here" merge, limited
> by pathspec, is the closest equivalent?

Sorry, but it is unclear to me what you mean by one-way "go here"
merge.  Do you mean oneway_merge() in unpack-trees.c?

--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Jeff King
On Tue, Sep 17, 2013 at 01:40:17PM -0700, Junio C Hamano wrote:

> > Hrm. Probably not. It is almost a one-way merge going to the named tree
> > (but limited by the pathspec), except that I think the current
> > git-checkout code may provide some safety checks related to where we are
> > coming from (e.g., do we unconditionally overwrite entries that are not
> > uptodate?).
> 
> I think we do unconditionally overwrite and that has been very much
> on purpose.

I thought so, too, but I was thrown off by the code in checkout_paths()
that warns/aborts if there are unmerged entries. But it looks like we
will have thrown out those entries already during the read_tree_some
call, which adds the new entries using OK_TO_REPLACE.

> "git checkout tree-ish -- file.txt" has always been about replacing
> whatever cruft is in paths in the worktree that match pathspec, just
> like "cat content-created-elsewhere >file.txt" is.  "Oops, you have
> a local change that do not match index" is the last thing we want to
> say, because getting rid of that local change is the primary reason
> why "checkout tree-ish -- file.txt" exists.
> 
> Taking the state of a subdirectory as a whole as "content", the
> change we are discussing will make it more like "rm -fr dir && tar
> xf some-content dir" to replace the directory wholesale, which I
> personally think is a good thing in the longer term.

Yeah, that makes sense. What about untracked files?

Right now we overwrite them if the tree-ish has an entry at the same
path; that is a bit more dangerous than the rest of git, but does match
the "ignore local modifications" rule. I assume if we handled deletions,
though, that we would simply leave them be.

So given that, is it fair to say that a one-way "go here" merge, limited
by pathspec, is the closest equivalent?

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Junio C Hamano
Jeff King  writes:

> On Tue, Sep 17, 2013 at 01:27:08PM -0700, Junio C Hamano wrote:
>
>> Jeff King  writes:
>> 
>> > On Tue, Sep 17, 2013 at 12:58:07PM -0700, Junio C Hamano wrote:
>> >
>> >> I could argue that the above intended behaviour is suboptimal and it
>> >> should have been "the resulting paths in the index and the work tree
>> >> that match the given pathspec must be identical to that of the
>> >> tree-ish".  In the resulting index or working tree, paths that match
>> >> "subdir" pathspec in the above result is subdir/a and subdir/b, and
>> >> that is different from what exists in the given tree-ish (which has
>> >> only subdir/a and not subdir/b), and under that modified definition,
>> >> what the current one does is not correct.
>> >
>> > Our emails just crossed, but I basically ended up saying a similar
>> > thing.  Could we simply replace the "update_some" in builtin/checkout.c
>> > with a two-way merge via unpack-trees?
>> 
>> Would it work to resolve a conflicted index by checking out from a
>> known tree?
>
> Hrm. Probably not. It is almost a one-way merge going to the named tree
> (but limited by the pathspec), except that I think the current
> git-checkout code may provide some safety checks related to where we are
> coming from (e.g., do we unconditionally overwrite entries that are not
> uptodate?).

I think we do unconditionally overwrite and that has been very much
on purpose.

"git checkout tree-ish -- file.txt" has always been about replacing
whatever cruft is in paths in the worktree that match pathspec, just
like "cat content-created-elsewhere >file.txt" is.  "Oops, you have
a local change that do not match index" is the last thing we want to
say, because getting rid of that local change is the primary reason
why "checkout tree-ish -- file.txt" exists.

Taking the state of a subdirectory as a whole as "content", the
change we are discussing will make it more like "rm -fr dir && tar
xf some-content dir" to replace the directory wholesale, which I
personally think is a good thing in the longer term.
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Jeff King
On Tue, Sep 17, 2013 at 01:27:08PM -0700, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > On Tue, Sep 17, 2013 at 12:58:07PM -0700, Junio C Hamano wrote:
> >
> >> I could argue that the above intended behaviour is suboptimal and it
> >> should have been "the resulting paths in the index and the work tree
> >> that match the given pathspec must be identical to that of the
> >> tree-ish".  In the resulting index or working tree, paths that match
> >> "subdir" pathspec in the above result is subdir/a and subdir/b, and
> >> that is different from what exists in the given tree-ish (which has
> >> only subdir/a and not subdir/b), and under that modified definition,
> >> what the current one does is not correct.
> >
> > Our emails just crossed, but I basically ended up saying a similar
> > thing.  Could we simply replace the "update_some" in builtin/checkout.c
> > with a two-way merge via unpack-trees?
> 
> Would it work to resolve a conflicted index by checking out from a
> known tree?

Hrm. Probably not. It is almost a one-way merge going to the named tree
(but limited by the pathspec), except that I think the current
git-checkout code may provide some safety checks related to where we are
coming from (e.g., do we unconditionally overwrite entries that are not
uptodate?).

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Junio C Hamano
Jeff King  writes:

> On Tue, Sep 17, 2013 at 12:58:07PM -0700, Junio C Hamano wrote:
>
>> I could argue that the above intended behaviour is suboptimal and it
>> should have been "the resulting paths in the index and the work tree
>> that match the given pathspec must be identical to that of the
>> tree-ish".  In the resulting index or working tree, paths that match
>> "subdir" pathspec in the above result is subdir/a and subdir/b, and
>> that is different from what exists in the given tree-ish (which has
>> only subdir/a and not subdir/b), and under that modified definition,
>> what the current one does is not correct.
>
> Our emails just crossed, but I basically ended up saying a similar
> thing.  Could we simply replace the "update_some" in builtin/checkout.c
> with a two-way merge via unpack-trees?

Would it work to resolve a conflicted index by checking out from a
known tree?

>> I vaguely recall arguing for the updated behaviour described in the
>> above paragraph, and I even might have started working on it, but I
>> do not think we changed this behaviour recently, unfortunately.
>
> Yes, I did some digging and I think it has always been this way, even
> before git-checkout was a builtin.
>
> -Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Jeff King
On Tue, Sep 17, 2013 at 09:06:59PM +0200, Uwe Kleine-König wrote:

>   $ git checkout HEAD^ -- subdir
> 
> I'd expect that subdir/b is removed from the index as this file didn't
> exist in HEAD^ but git-status only reports:

I'm not sure if this is intentional or not. The definition of "git
checkout $tree $path" given in commit 0a1283b says:

Checking paths out of a tree is (currently) defined to do:

 - Grab the paths from the named tree that match the given pathspec,
   and add them to the index;

 - Check out the contents from the index for paths that match the
   pathspec to the working tree; and while at it

 - If the given pathspec did not match anything, suspect a typo from the
   command line and error out without updating the index nor the working
   tree.

So we are applying the pathspec to the named tree, and pulling anything
that matches into the index. Which by definition cannot involve a
deletion, because there is no comparison happening (so we either have
it, or we do not). Whereas what you are expecting is to compare the tree
and the index, limited by the pathspec, and pull any changes from the
tree into the index.

I tend to agree that the latter is more like how other git commands
behave (e.g., if you tried to use "read-tree" to emulate what
git-checkout was doing, I think you would end up with a two-way merge).
But there may be implications I haven't thought of.

Note also that "git checkout -p" does present "subdir/b" as a deletion.
It works by doing a pathspec-limited diff between the two endpoints,
which will notice deletions. So there is some inconsistency there with
the baseline form.

-Peff
--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Junio C Hamano
Uwe Kleine-König   writes:

> after these commands:
>
>   $ git init
>   $ mkdir subdir
>   $ echo a > subdir/a
>   $ git add subdir/a
>   $ git commit -m a
>   $ echo more a >> subdir/a
>   $ echo b > subdir/b
>   $ git add subdir/*
>   $ git commit -m b
>   $ git checkout HEAD^ -- subdir
>
> I'd expect that subdir/b is removed from the index as this file didn't
> exist in HEAD^ but git-status only reports:
>
>   # On branch master
>   # Changes to be committed:
>   #   (use "git reset HEAD ..." to unstage)
>   #
>   #   modified:   subdir/a
>   #
>
> Is this intended?
>
> (I'm using git 1.8.4.rc3 as shipped by Debian (package version
> 1:1.8.4~rc3-1).)

The intended behaviour of "git checkout tree-ish -- pathspec" has
always been "grab paths that match pathspec from tree-ish, add them
to the index and check them out to the working tree".  If you have
subdir/b in the index and the working tree, it will be kept when the
paths that match "subdir" pathspec is grabbed out of the tree-ish
HEAD^ (namely, subdir/a) is added to the index and to the working
tree.

I could argue that the above intended behaviour is suboptimal and it
should have been "the resulting paths in the index and the work tree
that match the given pathspec must be identical to that of the
tree-ish".  In the resulting index or working tree, paths that match
"subdir" pathspec in the above result is subdir/a and subdir/b, and
that is different from what exists in the given tree-ish (which has
only subdir/a and not subdir/b), and under that modified definition,
what the current one does is not correct.

I vaguely recall arguing for the updated behaviour described in the
above paragraph, and I even might have started working on it, but I
do not think we changed this behaviour recently, unfortunately.

--
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


Re: [BUG?] git checkout $commit -- somedir doesn't drop files

2013-09-17 Thread Jeff King
On Tue, Sep 17, 2013 at 12:58:07PM -0700, Junio C Hamano wrote:

> I could argue that the above intended behaviour is suboptimal and it
> should have been "the resulting paths in the index and the work tree
> that match the given pathspec must be identical to that of the
> tree-ish".  In the resulting index or working tree, paths that match
> "subdir" pathspec in the above result is subdir/a and subdir/b, and
> that is different from what exists in the given tree-ish (which has
> only subdir/a and not subdir/b), and under that modified definition,
> what the current one does is not correct.

Our emails just crossed, but I basically ended up saying a similar
thing.  Could we simply replace the "update_some" in builtin/checkout.c
with a two-way merge via unpack-trees?

> I vaguely recall arguing for the updated behaviour described in the
> above paragraph, and I even might have started working on it, but I
> do not think we changed this behaviour recently, unfortunately.

Yes, I did some digging and I think it has always been this way, even
before git-checkout was a builtin.

-Peff
--
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