Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

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

Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:51:26

Jeff King [off-list ref] writes:
As you can see, this handles only three typoes of locations: the
Is that a recursive typo, or a typo of type?
worktree, the index, and an arbitrary commit (really a tree-ish).
Some other types I've thought of are:

  - stashes; you can already use stashes a source with "stash@{0}". They
    could also be a destination, chaining to "git stash".
No opinion on this.
  - branches as destinations; obviously we can't change an existing
    commit, but what about something like:

      git put WORKTREE BRANCH:foo

    to optionally create a new branch "refs/heads/foo" based on the
    current HEAD, push changes into a temporary index that matches its
    tip, and then making a new commit based on top.

    This would serve a similar purpose to stashes, except that they
    would be named and could operate as full branches. I would find it
    useful for picking apart a mass of worktree changes into discrete
    commits.
Should "git put WORKTREE HEAD" be equivalent to "git commit -A" then?
  - allow multiple destinations, like

     # equivalent to "git checkout --"
     git put HEAD INDEX,WORKTREE
This is close to going overboard, but OK.
  - blobs as locations. We could allow something like:

      git put v1.7.5:Makefile WORKTREE:Makefile

    which would be equivalent to

      git put v1.7.5 WORKTREE -- Makefile

    but sometimes matches the user's mental model better. It also allows
    pulling blobs from index stages, like:

      # Resolve in favor of "ours"
      git put :2:Makefile INDEX,WORKTREE
More importantly, it would allow people to do things like...

	git put v1.7.5:Makefile WORKTREE:oMakefile
        magicdiff oMakefile Makefile
  - subtrees as locations. This allows a form of renaming between old
    versions.

      git put gitgui-0.10.0: WORKTREE:git-gui
This is a natural extension of the above "we could rename" theme, right?
...  Of course, it may also just introduce insane
confusion.
The only worry about confusion is if people incorrectly think these magic
tokens are not mere syntax sugars available only in "put", especially,
they look so similar to "HEAD" which is _not_ syntax sugar and can be used
elsewhere. Other than that, I think this is a nice approach.

Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

From: Jeff King <hidden>
Date: 2016-06-15 22:51:26

On Tue, Jun 07, 2011 at 02:04:55PM -0700, Junio C Hamano wrote:
quoted
As you can see, this handles only three typoes of locations: the
Is that a recursive typo, or a typo of type?
It's art; the viewer is free to interpret based on their own
experiences.
quoted
Some other types I've thought of are:

  - stashes; you can already use stashes a source with "stash@{0}". They
    could also be a destination, chaining to "git stash".
No opinion on this.
My initial prototype was going to have stash as a fourth location. But I
backed out a little because it was complex, and the more I think about
it, I'm not sure it's really appropriate. You can already pull _from_ a
stash by naming its commit. And putting into a stash is a bit different
than a put, because it handles both the index and the worktree, and
removes the changes from them afterwards.

So I think a better match is the idea of "git put" to a new commit on a
named branch that I showed elsewhere. And then you can "git put" off of
it later.
quoted
  - branches as destinations; obviously we can't change an existing
    commit, but what about something like:

      git put WORKTREE BRANCH:foo

    to optionally create a new branch "refs/heads/foo" based on the
    current HEAD, push changes into a temporary index that matches its
    tip, and then making a new commit based on top.
Should "git put WORKTREE HEAD" be equivalent to "git commit -A" then?
I'm tempted to say yes, with two reservations:

  1. Making a new commit (or even a new branch) somehow seems more
     heavyweight to me than just picking changes. So I'm reluctant to do
     it for just "git put $from HEAD"; maybe there should be a special
     token that says "yeah, make a new commit". Like:

       git put WORKTREE COMMIT:HEAD

     to commit on top of HEAD, or even

       git put WORKTREE AMEND:HEAD

     to amend HEAD (this would be useful when building up a commit
     piece by piece using "git put").

     But that is getting very magical. I have a vague feeling you could
     actually reimplement a lot of the user-facing portions of git in
     terms of these "put" operations. For example, forget the index as a
     whole and have "NEXT", "BASE", "OURS", and "THEIRS" representing
     trees of the various stages.

     I'm not sure if that's just insane, though. That _isn't_ how the
     index actually works (e.g., resolved paths would have only a NEXT
     entry, so the other trees would actually be partial trees). So
     we're making an abstraction over it, and when that abstraction
     leaks, I fear things will get very confusing for the user.

  2. There is a slight incompatibility between the "git put" mental
     model and what really happens. I already ran into it once with "git
     put HEAD WORKTREE", and it appears here again. The issue is that
     you generally _don't_ put items straight from a commit to the
     worktree and vice versa. They go through the index.

     So I took care with "git put HEAD WORKTREE" that the index was not
     touched. That makes the command very obvious and keeps the sources
     and destinations as orthogonal as possible. But is it really what
     the user wants? In the case of "checkout", I'm not sure. In the
     case of "commit -A", you probably _do_ want to update the index if
     the commit is HEAD, and _don't_ if it is another branch.

     But now we're getting magical again. So the question becomes:
     should git put just be a pure _wrapper_ around these other
     commands to aid in discoverability, and do sensible things for each
     combination, or should it be a purely orthogonal "pick content from
     source to destination" command?
quoted
  - allow multiple destinations, like

     # equivalent to "git checkout --"
     git put HEAD INDEX,WORKTREE
This is close to going overboard, but OK.
Yeah, I'm still kind of brainstorming, but I think you might be right.
But see above for why "git put" should possibly just be doing it for
you automatically.
quoted
  - subtrees as locations. This allows a form of renaming between old
    versions.

      git put gitgui-0.10.0: WORKTREE:git-gui
This is a natural extension of the above "we could rename" theme, right?
Yeah, I think so.
The only worry about confusion is if people incorrectly think these magic
tokens are not mere syntax sugars available only in "put", especially,
they look so similar to "HEAD" which is _not_ syntax sugar and can be used
elsewhere. Other than that, I think this is a nice approach.
I think it might be worth using the same tokens in "diff", but yeah,
they definitely should not go elsewhere.

I find the all-caps ugly, and it is part of what confuses them with
HEAD. At the same time, we are using the same namespace that ref lookup
uses. So calling it "worktree" might be too ambiguous. I tried to avoid
using "--worktree" because I wanted to make it clear that these were
ordered arguments, not options.

There's also one other complication with the whole idea, which is that
there are two separate things you might want to move: content itself, or
_changes_ in content.

That is, think about the way stashes work. We don't apply the difference
between the stashed content and our working tree. We look at the
difference between the stashed content and its parent, and then apply
those changes to the working tree.

When I do "checkout -p $commit $file", I am often not interested in
seeing all of the differences between where I am now and where $commit
is, but rather in seeing the differences introduced by $commit, and
pulling them selectively into my current version of $file. Sort of a
"cherry-pick -p".

Should "put" support that kind of usage? What would it look like?

  git put commit:v1.7.5 WORKTREE Makefile

? Or even:

  git put v1.7.4..v1.7.5 WORKTREE Makefile

I dunno. Maybe this whole thing is too crazy. I'll think on it some
more, and maybe some other people will comment.

-Peff

Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

From: Michael Nahas <hidden>
Date: 2016-06-15 22:51:26

Junio wrote:
The only worry about confusion is if people incorrectly think these magic
tokens are not mere syntax sugars available only in "put", especially,
they look so similar to "HEAD" which is _not_ syntax sugar and can be used
elsewhere. Other than that, I think this is a nice approach.
I don't think they are syntactic sugar.

The working tree is a tree.  HEAD is a tree.  HEAD is also a commit
and a file in .git/, so it is more than a tree, but it's a tree.  NEXT
is a tree.   There may be different code to read (or write) each of
them, but they are all trees.  So I don't see these labels as
syntactic sugar -- making a commonly used piece of code easier to use
(like ++) -- but as presenting a common interface to a concept that
may have different implementations.

I think this "git put" command let's people think in terms of trees.
Commits are read-only trees.  NEXT and WTREE are tree that can be
written to.  It's up for debate if stashes are read-only or writeable.

To me "git put" is just the UNIX "cp" command, just that files or
directories can be prefixed by tree names.  In fact, I'd make sure the
"-r" option was used when copying whole trees or subtrees. :)

git put -r HEAD WTREE
git put HEAD:foo.txt WTREE:foo.txt

I would keep it like "cp" and drop the support for copying to multiple
trees (like HEAD and INDEX) in a single command.  I would have a good
form for copying multiple files from one tree to another.  E.g., "git
put HEAD:{foo.txt,bar.txt} WTREE" or "git put HEAD WTREE foo.txt
bar.txt" or "git put HEAD:*.txt WTREE" even.

I do not think "COMMIT" or "AMEND" should be part of the command.

"git put" could replace "git add", "git checkout -- <file>", and "git
reset -- <file>".  It would not replace the other common file
manipulators: "git rm" and "git mv".

Damn, I'm tempted to say screw "git put" and call it "git cp".  Then
change "git rm" and "git mv" to support writeable trees and you've got
yourself a very easy to learn interface!


Jeff wrote:
The issue is that
you generally _don't_ put items straight from a commit to the
worktree and vice versa. They go through the index.
Going through the index is only the right move if you're going backwards.

HEAD is the most recent commit.  NEXT should be what you already know
will go in the next commit.  WTREE is stuff that may go into NEXT or
into another future commit or may never go in at all.   So, HEAD and
all previous commits are the past; NEXT is the near future; and WTREE
is the far future.

If you are reverting a mistake, you are copying from HEAD or some
other ancestor to NEXT and WTREE.  Especially if you're copying from
HEAD, you want to include the target NEXT, since you know that that
code will almost assuredly work and be part of the next commit.  In
fact, the opposite of "git add" (the awkward "git checkout -- <file>")
is to copy a file from HEAD to NEXT --- essentially pushing off the
change from NEXT to some future commit.

In every other case, you want new stuff to go into WTREE and skip the
NEXT.  The way I view merge is that the new files are copied from
another branch into WTREE.  All resolved changes are then moved into
NEXT.  If there are no unresolved changed, a new commit is made.
While this may not be the actual sequence of events that Git performs,
it's how I see the operation - new changes are introduced at WTREE,
correct changes are moved into NEXT, and the commit operation makes
them permanent.





On Tue, Jun 7, 2011 at 5:45 PM, Jeff King [off-list ref] wrote:
On Tue, Jun 07, 2011 at 02:04:55PM -0700, Junio C Hamano wrote:
quoted
quoted
As you can see, this handles only three typoes of locations: the
Is that a recursive typo, or a typo of type?
It's art; the viewer is free to interpret based on their own
experiences.
quoted
quoted
Some other types I've thought of are:

  - stashes; you can already use stashes a source with "stash@{0}". They
    could also be a destination, chaining to "git stash".
No opinion on this.
My initial prototype was going to have stash as a fourth location. But I
backed out a little because it was complex, and the more I think about
it, I'm not sure it's really appropriate. You can already pull _from_ a
stash by naming its commit. And putting into a stash is a bit different
than a put, because it handles both the index and the worktree, and
removes the changes from them afterwards.

So I think a better match is the idea of "git put" to a new commit on a
named branch that I showed elsewhere. And then you can "git put" off of
it later.
quoted
quoted
  - branches as destinations; obviously we can't change an existing
    commit, but what about something like:

      git put WORKTREE BRANCH:foo

    to optionally create a new branch "refs/heads/foo" based on the
    current HEAD, push changes into a temporary index that matches its
    tip, and then making a new commit based on top.
Should "git put WORKTREE HEAD" be equivalent to "git commit -A" then?
I'm tempted to say yes, with two reservations:

 1. Making a new commit (or even a new branch) somehow seems more
    heavyweight to me than just picking changes. So I'm reluctant to do
    it for just "git put $from HEAD"; maybe there should be a special
    token that says "yeah, make a new commit". Like:

      git put WORKTREE COMMIT:HEAD

    to commit on top of HEAD, or even

      git put WORKTREE AMEND:HEAD

    to amend HEAD (this would be useful when building up a commit
    piece by piece using "git put").

    But that is getting very magical. I have a vague feeling you could
    actually reimplement a lot of the user-facing portions of git in
    terms of these "put" operations. For example, forget the index as a
    whole and have "NEXT", "BASE", "OURS", and "THEIRS" representing
    trees of the various stages.

    I'm not sure if that's just insane, though. That _isn't_ how the
    index actually works (e.g., resolved paths would have only a NEXT
    entry, so the other trees would actually be partial trees). So
    we're making an abstraction over it, and when that abstraction
    leaks, I fear things will get very confusing for the user.

 2. There is a slight incompatibility between the "git put" mental
    model and what really happens. I already ran into it once with "git
    put HEAD WORKTREE", and it appears here again. The issue is that
    you generally _don't_ put items straight from a commit to the
    worktree and vice versa. They go through the index.

    So I took care with "git put HEAD WORKTREE" that the index was not
    touched. That makes the command very obvious and keeps the sources
    and destinations as orthogonal as possible. But is it really what
    the user wants? In the case of "checkout", I'm not sure. In the
    case of "commit -A", you probably _do_ want to update the index if
    the commit is HEAD, and _don't_ if it is another branch.

    But now we're getting magical again. So the question becomes:
    should git put just be a pure _wrapper_ around these other
    commands to aid in discoverability, and do sensible things for each
    combination, or should it be a purely orthogonal "pick content from
    source to destination" command?
quoted
quoted
  - allow multiple destinations, like

     # equivalent to "git checkout --"
     git put HEAD INDEX,WORKTREE
This is close to going overboard, but OK.
Yeah, I'm still kind of brainstorming, but I think you might be right.
But see above for why "git put" should possibly just be doing it for
you automatically.
quoted
quoted
  - subtrees as locations. This allows a form of renaming between old
    versions.

      git put gitgui-0.10.0: WORKTREE:git-gui
This is a natural extension of the above "we could rename" theme, right?
Yeah, I think so.
quoted
The only worry about confusion is if people incorrectly think these magic
tokens are not mere syntax sugars available only in "put", especially,
they look so similar to "HEAD" which is _not_ syntax sugar and can be used
elsewhere. Other than that, I think this is a nice approach.
I think it might be worth using the same tokens in "diff", but yeah,
they definitely should not go elsewhere.

I find the all-caps ugly, and it is part of what confuses them with
HEAD. At the same time, we are using the same namespace that ref lookup
uses. So calling it "worktree" might be too ambiguous. I tried to avoid
using "--worktree" because I wanted to make it clear that these were
ordered arguments, not options.

There's also one other complication with the whole idea, which is that
there are two separate things you might want to move: content itself, or
_changes_ in content.

That is, think about the way stashes work. We don't apply the difference
between the stashed content and our working tree. We look at the
difference between the stashed content and its parent, and then apply
those changes to the working tree.

When I do "checkout -p $commit $file", I am often not interested in
seeing all of the differences between where I am now and where $commit
is, but rather in seeing the differences introduced by $commit, and
pulling them selectively into my current version of $file. Sort of a
"cherry-pick -p".

Should "put" support that kind of usage? What would it look like?

 git put commit:v1.7.5 WORKTREE Makefile

? Or even:

 git put v1.7.4..v1.7.5 WORKTREE Makefile

I dunno. Maybe this whole thing is too crazy. I'll think on it some
more, and maybe some other people will comment.

-Peff

Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

From: Jakub Narebski <hidden>
Date: 2016-06-15 22:51:26

Jeff King [off-list ref] writes:
I find the all-caps ugly, and it is part of what confuses them with
HEAD. At the same time, we are using the same namespace that ref lookup
uses. So calling it "worktree" might be too ambiguous. I tried to avoid
using "--worktree" because I wanted to make it clear that these were
ordered arguments, not options.
Perhaps we can use some character that is forbidden in ref names,
doesn't make trouble when doing allowed operations on said refs, won't
confuse user, and is not trouble with shell... ehhh...

* @{wtree} would confuse users that it has something to do with reflog
* [tree]   would be trouble with some shells
* ~tree~   looks a bit strange, might be trouble with username expansion  
* :tree:   might be mistaken for 'tree:' in index

-- 
Jakub Narebski
Poland
ShadeHawk on #git

Re: [RFC/PATCH] git put: an alternative to add/reset/checkout

From: Nguyen Thai Ngoc Duy <hidden>
Date: 2016-06-15 22:51:27

On Thu, Jun 9, 2011 at 12:25 AM, Jakub Narebski [off-list ref] wrote:
Perhaps we can use some character that is forbidden in ref names,
doesn't make trouble when doing allowed operations on said refs, won't
confuse user, and is not trouble with shell... ehhh...

* :tree:   might be mistaken for 'tree:' in index
Also may clash (or make it more ambiguous) with pathspec magic. Another option

* +tree
-- 
Duy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help