Re: [RFC/PATCH] git put: an alternative to add/reset/checkout
- From
Nguyen Thai Ngoc Duy <pclouds@gmail.com>
- Date
- Jan 23, 2012, 10:32 UTC
- Message-ID
- <CACsJy8BCGi3s8gXr4kk-u8tDWztV6ozg1Tap23Q=TxA5d9iL+g@mail.gmail.com>
- In-Reply-To
- <20110607200659.GA6177@sigill.intra.peff.net>
(Bringing up an old thread)
On Wed, Jun 8, 2011 at 3:06 AM, Jeff King <peff@peff.net> wrote:
Show 116 quoted lines
> ...
> 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.
Show 20 quoted lines
> 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