* [PATCH v5 1/8] detached-stash: introduce parse_flags_and_revs function
2010-08-18 13:09 [PATCH v5 0/8] detached-stash: regularise handling of stash arguments by git stash Jon Seymour
@ 2010-08-18 13:09 ` Jon Seymour
2010-08-18 13:09 ` [PATCH v5 2/8] detached-stash: simplify stash_apply Jon Seymour
2010-08-18 13:09 ` [PATCH v5 3/8] detached-stash: simplify stash_drop Jon Seymour
2 siblings, 0 replies; 4+ messages in thread
From: Jon Seymour @ 2010-08-18 13:09 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, Jon Seymour
Introduce parse_flags_and_revs. This function requires that
there is at at most one stash-like revision parameter and
sero or more flags.
It knows how to parse -q,--quiet and --index flags, but leaves
other flags unparsed.
Specified revisions are checked to see that they are at least stash-like
(meaning: they look like something created by git stash save or git stash
create).
If this is so, then IS_STASH_LIKE is initialized to a non-empty value.
If the specified revision also looks like a stash log entry reference,
then IS_STASH_REF is initialized to a non-empty value.
References of the form ref@{spec} are required to precisely identify
an individual commit.
If no reference is specified, stash@{0} is assumed.
Once the specified reference is validated to be at least stash_like
a ensemble of derived variables, (w_commit, w_tree, b_commit, etc)
are initialized with a single call to git rev-parse.
Repeated calls to parse_flags_and_rev() avoid repeated calls
to git rev-parse if the specified arguments have already been
parsed.
An ensemble of supporting functions that make use of the state
established by parse_flags_and_rev(). These are describe below.
Subsequent patches in the series modify the existing
git stash subcommands to make use of these functions as appropriate.
The ancillary functions are:
is_stash_like(): which can be used to test
whether a specified commit looks like a commit created with
git stash save or git stash create.
assert_stash_like(): which can be used by
commands that misbehave unless their arguments stash-like.
is_stash_ref(): which checks whether an argument
is valid stash reference(e.g. is of the form
['refs/']stash['@{'something'}])
assert_stash_ref(): which can be used by commands
that misbehave unless their arguments are both stash-like and
refer to valid stash entries.
Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
git-stash.sh | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 133 insertions(+), 0 deletions(-)
diff --git a/git-stash.sh b/git-stash.sh
index 1d95447..42b0da2 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -225,6 +225,138 @@ show_stash () {
git diff $flags $b_commit $w_commit
}
+#
+# Parses the remaining options looking for flags and
+# at most one revision defaulting to ${ref_stash}@{0}
+# if none found.
+#
+# Derives related tree and commit objects from the
+# revision, if one is found.
+#
+# stash records the work tree, and is a merge between the
+# base commit (first parent) and the index tree (second parent).
+#
+# REV is set to the symbolic version of the specified stash-like commit
+# IS_STASH_LIKE is non-blank if ${REV} looks like a stash
+# IS_STASH_REF is non-blank if the ${REV} looks like a stash ref
+# s is set to the SHA1 of the stash commit
+# w_commit is set to the commit containing the working tree
+# b_commit is set to the base commit
+# i_commit is set to the commit containing the index tree
+# w_tree is set to the working tree
+# b_tree is set to the base tree
+# i_tree is set to the index tree
+#
+# GIT_QUIET is set to t if -q is specified
+# INDEX_OPTION is set to --index if --index is specified.
+# FLAGS is set to the remaining flags
+#
+# dies if:
+# * too many revisions specified
+# * no revision is specified and there is no stash stack
+# * a revision is specified which cannot be resolve to a SHA1
+# * a non-existent stash reference is specified
+#
+
+parse_flags_and_rev()
+{
+ test "$PARSE_CACHE" = "$*" && return 0 # optimisation
+ PARSE_CACHE="$*"
+
+ IS_STASH_LIKE=
+ IS_STASH_REF=
+ INDEX_OPTION=
+ s=
+ w_commit=
+ b_commit=
+ i_commit=
+ w_tree=
+ b_tree=
+ i_tree=
+
+ REV=$(git rev-parse --no-flags --symbolic "$@" 2>/dev/null)
+ FLAGS=$(git rev-parse --no-revs -- "$@" 2>/dev/null)
+
+ set -- $FLAGS
+
+ FLAGS=
+ while test $# -ne 0
+ do
+ case "$1" in
+ -q|--quiet)
+ GIT_QUIET=-t
+ ;;
+ --index)
+ INDEX_OPTION=--index
+ ;;
+ --)
+ :
+ ;;
+ *)
+ FLAGS="${FLAGS}${FLAGS:+ }$1"
+ ;;
+ esac
+ shift
+ done
+
+ set -- $REV
+
+ case $# in
+ 0)
+ have_stash || die "No stash found."
+ set -- ${ref_stash}@{0}
+ ;;
+ 1)
+ :
+ ;;
+ *)
+ die "Too many revisions specified: $REV"
+ ;;
+ esac
+
+ REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || die "$1 is not valid reference"
+
+ i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) &&
+ set -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) &&
+ s=$1 &&
+ w_commit=$1 &&
+ b_commit=$2 &&
+ w_tree=$3 &&
+ b_tree=$4 &&
+ i_tree=$5 &&
+ IS_STASH_LIKE=t &&
+ test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
+ IS_STASH_REF=t
+
+ if test "${REV}" != "${REV%{*\}}"
+ then
+ # maintainers: it would be better if git rev-parse indicated
+ # this condition with a non-zero status code but as of 1.7.2.1 it
+ # it did not. So, we use non-empty stderr output as a proxy for the
+ # condition of interest.
+ test -z "$(git rev-parse "$REV" 2>&1 >/dev/null)" || die "$REV does not exist in the stash log"
+ fi
+
+}
+
+is_stash_like()
+{
+ parse_flags_and_rev "$@"
+ test -n "$IS_STASH_LIKE"
+}
+
+assert_stash_like() {
+ is_stash_like "$@" || die "'$*' is not a stash-like commit"
+}
+
+is_stash_ref() {
+ is_stash_like "$@" && test -n "$IS_STASH_REF"
+}
+
+assert_stash_ref() {
+ is_stash_ref "$@" || die "'$*' is not a stash reference"
+}
+
apply_stash () {
applied_stash=
unstash_index=
@@ -375,6 +507,7 @@ apply_to_branch () {
drop_stash $stash
}
+PARSE_CACHE='--not-parsed'
# The default command is "save" if nothing but options are given
seen_non_option=
for opt
--
1.7.2.1.95.g4fabf
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v5 2/8] detached-stash: simplify stash_apply
2010-08-18 13:09 [PATCH v5 0/8] detached-stash: regularise handling of stash arguments by git stash Jon Seymour
2010-08-18 13:09 ` [PATCH v5 1/8] detached-stash: introduce parse_flags_and_revs function Jon Seymour
@ 2010-08-18 13:09 ` Jon Seymour
2010-08-18 13:09 ` [PATCH v5 3/8] detached-stash: simplify stash_drop Jon Seymour
2 siblings, 0 replies; 4+ messages in thread
From: Jon Seymour @ 2010-08-18 13:09 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, Jon Seymour
The implementation of stash_apply() is simplified to take
advantage of the common parsing function parse_flags_and_rev().
Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
git-stash.sh | 38 +++-----------------------------------
1 files changed, 3 insertions(+), 35 deletions(-)
diff --git a/git-stash.sh b/git-stash.sh
index 42b0da2..ba68f1e 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -358,40 +358,8 @@ assert_stash_ref() {
}
apply_stash () {
- applied_stash=
- unstash_index=
- while test $# != 0
- do
- case "$1" in
- --index)
- unstash_index=t
- ;;
- -q|--quiet)
- GIT_QUIET=t
- ;;
- *)
- break
- ;;
- esac
- shift
- done
-
- if test $# = 0
- then
- have_stash || die 'Nothing to apply'
- applied_stash="$ref_stash@{0}"
- else
- applied_stash="$*"
- fi
-
- # stash records the work tree, and is a merge between the
- # base commit (first parent) and the index tree (second parent).
- s=$(git rev-parse --quiet --verify --default $ref_stash "$@") &&
- w_tree=$(git rev-parse --quiet --verify "$s:") &&
- b_tree=$(git rev-parse --quiet --verify "$s^1:") &&
- i_tree=$(git rev-parse --quiet --verify "$s^2:") ||
- die "$*: no valid stashed state found"
+ assert_stash_like "$@"
git update-index -q --refresh &&
git diff-files --quiet --ignore-submodules ||
@@ -402,7 +370,7 @@ apply_stash () {
die 'Cannot apply a stash in the middle of a merge'
unstashed_index_tree=
- if test -n "$unstash_index" && test "$b_tree" != "$i_tree" &&
+ if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" &&
test "$c_tree" != "$i_tree"
then
git diff-tree --binary $s^2^..$s^2 | git apply --cached
@@ -447,7 +415,7 @@ apply_stash () {
else
# Merge conflict; keep the exit status from merge-recursive
status=$?
- if test -n "$unstash_index"
+ if test -n "$INDEX_OPTION"
then
echo >&2 'Index was not unstashed.'
fi
--
1.7.2.1.95.g4fabf
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v5 3/8] detached-stash: simplify stash_drop
2010-08-18 13:09 [PATCH v5 0/8] detached-stash: regularise handling of stash arguments by git stash Jon Seymour
2010-08-18 13:09 ` [PATCH v5 1/8] detached-stash: introduce parse_flags_and_revs function Jon Seymour
2010-08-18 13:09 ` [PATCH v5 2/8] detached-stash: simplify stash_apply Jon Seymour
@ 2010-08-18 13:09 ` Jon Seymour
2 siblings, 0 replies; 4+ messages in thread
From: Jon Seymour @ 2010-08-18 13:09 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, Jon Seymour
Previously, git stash drop would fail noisily while executing git reflog
delete if the specified revision was not a stash reference.
Now, git stash drop fails with an error message which more precisely
indicates the reason for failure.
Furthermore, git stash drop will now fail with a non-zero status code
if stash@{n} specifies a stash log entry that does not actually exist.
This change in behaviour is achieved by delegating argument parsing
to the common parse_flags_and_rev() function (via a call to
assert_stash_ref).
Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
git-stash.sh | 31 +++----------------------------
1 files changed, 3 insertions(+), 28 deletions(-)
diff --git a/git-stash.sh b/git-stash.sh
index ba68f1e..750f360 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -424,35 +424,10 @@ apply_stash () {
}
drop_stash () {
- have_stash || die 'No stash entries to drop'
+ assert_stash_ref "$@"
- while test $# != 0
- do
- case "$1" in
- -q|--quiet)
- GIT_QUIET=t
- ;;
- *)
- break
- ;;
- esac
- shift
- done
-
- if test $# = 0
- then
- set x "$ref_stash@{0}"
- shift
- fi
- # Verify supplied argument looks like a stash entry
- s=$(git rev-parse --verify "$@") &&
- git rev-parse --verify "$s:" > /dev/null 2>&1 &&
- git rev-parse --verify "$s^1:" > /dev/null 2>&1 &&
- git rev-parse --verify "$s^2:" > /dev/null 2>&1 ||
- die "$*: not a valid stashed state"
-
- git reflog delete --updateref --rewrite "$@" &&
- say "Dropped $* ($s)" || die "$*: Could not drop stash entry"
+ git reflog delete --updateref --rewrite "${REV}" &&
+ say "Dropped ${REV} ($s)" || die "${REV}: Could not drop stash entry"
# clear_stash if we just dropped the last stash entry
git rev-parse --verify "$ref_stash@{0}" > /dev/null 2>&1 || clear_stash
--
1.7.2.1.95.g4fabf
^ permalink raw reply related [flat|nested] 4+ messages in thread