(Bringing up an old thread) On Wed, Jun 8, 2011 at 3:06 AM, Jeff King <peff@xxxxxxxx> 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 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html