Re: [RFC/PATCH] git put: an alternative to add/reset/checkout
- From
- Michael Nahas <mike.nahas@gmail.com>
- Date
- Jan 23, 2012, 13:53 UTC
- Message-ID
- <CADo4Y9iH+J-X-TdqTN2Y9KhQnprnCVvC4Xy6qhVHwsBRmsZUrg@mail.gmail.com>
- In-Reply-To
- <CACsJy8BCGi3s8gXr4kk-u8tDWztV6ozg1Tap23Q=TxA5d9iL+g@mail.gmail.com>
On Mon, Jan 23, 2012 at 5:32 AM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> > (Bringing up an old thread)
"...thank you so much for bringing up such a painful subject. While you're at it, why don't you give me a nice paper cut and pour lemon juice on it."
"git put" is "git cp". It copies from one filesystem (or a snapshot of a filesystem) to another filesystem.
Without multiple working directories, a modifiable "stash", or a (useful) name for the filesystem referred to as "index"/"cache"/"staging area", there is only one filesystem that the command can write to: the (singular) working directory.
So, "git put <src filesystem> -- <path>" is fine. It will copy from the path in the src filesystem to the path in the current working directory. I don't think the command "put" is a great name for that. Since we already have some strange double-usage commands like "git checkout --" and "git reset --", perhaps this should be "git cherry-pick --".
<rant> But for my money, "git cp" is clearer and I'd love to get rid of the user-confusing double-usage commands. I'd replace "git checkout --" with "git cp NEXT WTREE -- <path>" and replace "git reset --" with "git cp HEAD NEXT --" where NEXT is the filesystem represented by the "index"/"cache"/"staging area" and WTREE is an alias for the working directory. </rant>
Still, good luck. It's a useful addition even if it is "git cherry-pick --".
Mike
Show 178 quoted lines
>
>
> On Wed, Jun 8, 2011 at 3:06 AM, Jeff King <peff@peff.net> wrote:
> > ...
> > But another way to think about it is that commits, the index, and the
> > working tree are all "locations" with content. And one common operation
> > you may want to do is to move content from one spot to another, either
> > whole, by file, or by diff hunks. To a new user, knowing that "add" is
> > the command for moving content from thet working tree to the index does
> > not help them know which command to use to do the opposite content
> > movement.
> > ...
> > My idea is therefore to have a single command for moving content from
> > one location to another. You specify a source and a destination and get
> > a uniform interface for moving content.
> >
> > A proof-of-concept patch is below. Be aware that is meant to be
> > illustrative and is not well tested. Also, it is a minimal presentation
> > of the concept. Other "locations" may also be meaningful. I'll include
> > some ideas below the patch.
> >
> > ---
> > Makefile | 1 +
> > git-put.sh | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 71 insertions(+), 0 deletions(-)
> > create mode 100644 git-put.sh
> >
> > diff --git a/Makefile b/Makefile
> > index e40ac0c..4564506 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -368,6 +368,7 @@ SCRIPT_SH += git-merge-one-file.sh
> > SCRIPT_SH += git-merge-resolve.sh
> > SCRIPT_SH += git-mergetool.sh
> > SCRIPT_SH += git-pull.sh
> > +SCRIPT_SH += git-put.sh
> > SCRIPT_SH += git-quiltimport.sh
> > SCRIPT_SH += git-rebase.sh
> > SCRIPT_SH += git-repack.sh
> > diff --git a/git-put.sh b/git-put.sh
> > new file mode 100644
> > index 0000000..f673e14
> > --- /dev/null
> > +++ b/git-put.sh
> > @@ -0,0 +1,70 @@
> > +#!/bin/sh
> > +
> > +SUBDIRECTORY_OK=Yes
> > +OPTIONS_KEEPDASHASH=Yes
> > +OPTIONS_SPEC="\
> > +git put [options] <from> <to> [--] <file...>
> > +
> > +Move contents from one place to another, where <from> and <to> are one of:
> > + 1. A commit (e.g., master, HEAD~10, v1.7.5)
> > + 2. The special token INDEX to indicate git's index.
> > + 3. The special token WORKTREE to indicate the working directory.
> > +
> > +Options:
> > +--
> > +p don't move whole files; use the patch interface
> > +"
> > +. git-sh-setup
> > +
> > +patch=
> > +while test $# != 0; do
> > + case "$1" in
> > + -p) patch=--patch ;;
> > + --) shift; break ;;
> > + *) usage ;;
> > + esac
> > + shift
> > +done
> > +test $# -lt 2 && usage
> > +
> > +from=$1; shift
> > +to=$1; shift
> > +test "$1" = "--" && shift
> > +
> > +type_of() {
> > + case "$1" in
> > + INDEX) echo index ;;
> > + WORKTREE) echo worktree ;;
> > + *) echo commit ;;
> > + esac
> > +}
> > +
> > +# Checkout contents to worktree without munging the index in
> > +# between.
> > +worktree_checkout() {
> > + old=$GIT_INDEX_FILE
> > + test -z "$old" && old=$(git rev-parse --git-dir)/index
> > + new=$(git rev-parse --git-dir)/put-index.tmp
> > + cp "$old" "$new" &&
> > + GIT_INDEX_FILE=$new git checkout "$@"
> > + status=$?
> > + rm -f "$new"
> > + exit $status
> > +}
> > +
> > +case "$(type_of "$from"),$(type_of "$to")" in
> > +*,commit)
> > + die "You can't modify an existing commit." ;;
> > +index,index)
> > + die "You can't move content from the index on top of itself." ;;
> > +worktree,index)
> > + exec git add $patch -- "$@" ;;
> > +commit,index)
> > + exec git reset $patch "$from" -- "$@" ;;
> > +index,worktree)
> > + exec git checkout $patch -- "$@" ;;
> > +worktree,worktree)
> > + die "You can't move content in the worktree on top of itself." ;;
> > +commit,worktree)
> > + worktree_checkout $patch "$from" -- "$@" ;;
> > +esac
> >
> >
> > As you can see, this handles only three typoes of locations: the
> > worktree, the index, and an arbitrary commit (really a tree-ish).
>
> Last time we were stuck at the magic keywords INDEX and WORKTREE. What
> if we sort of follow scp naming convention:
>
> - Normal paths are working tree's paths
> - Paths with a colon in it are in "remote" locations (index or a
> tree). The part before colon specifies the location.
>
> We could have:
>
> git put <src> [<src>...] <dst>
> git put <src> [<src>...] <dst> -- <pathspec>
>
> Where <src> and <dst> could be
>
> - <tree-ish> <colon> [<pathspec>]
> - [0-3] <colon> [<pathspec>]
> - <pathspec> (or plain path)
>
> In the first form, pathspec could be specified in <src>. If <dst> is
> worktree, then "." would be enough (or path to repo's root to be more
> strict). In the second form, no pathspec can be part of <src> nor
> <dst> because they're at the end already.
>
> With this syntax we could have:
>
> git put 0:path/to/file.c . (or git put 0: path/to/file.c)
> -> copy file.c from index to worktree (at the same path "path/to/file.c")
> git put path/to/file 0:
> -> copy file to index
> git put HEAD: . -- path/
> -> checkout everything in path/ from HEAD
>
> I'm not sure how mutiple <src> should work, but there may be a use case for it.
>
> > Some other types I've thought of are:
> > ...
> > - 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.
> >
> > - allow multiple destinations, like
> >
> > # equivalent to "git checkout --"
> > git put HEAD INDEX,WORKTREE
>
> These obviously do not work with the syntax I propose.
> --
> Duy