Merge branch 'da/rev-parse-verify-quiet'

"rev-parse --verify --quiet $name" is meant to quietly exit with a
non-zero status when $name is not a valid object name, but still
gave error messages in some cases.

* da/rev-parse-verify-quiet:
  stash: prefer --quiet over shell redirection of the standard error stream
  refs: make rev-parse --quiet actually quiet
  t1503: use test_must_be_empty
  Documentation: a note about stdout for git rev-parse --verify --quiet
This commit is contained in:
Junio C Hamano
2014-09-29 12:36:10 -07:00
8 changed files with 71 additions and 27 deletions

View File

@ -114,6 +114,7 @@ can be used.
Only meaningful in `--verify` mode. Do not output an error Only meaningful in `--verify` mode. Do not output an error
message if the first argument is not a valid object name; message if the first argument is not a valid object name;
instead exit with non-zero status silently. instead exit with non-zero status silently.
SHA-1s for valid object names are printed to stdout on success.
--sq:: --sq::
Usually the output is made one line per flag and Usually the output is made one line per flag and

View File

@ -508,7 +508,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
int has_dashdash = 0; int has_dashdash = 0;
int output_prefix = 0; int output_prefix = 0;
unsigned char sha1[20]; unsigned char sha1[20];
unsigned int flags = 0;
const char *name = NULL; const char *name = NULL;
struct object_context unused;
if (argc > 1 && !strcmp("--parseopt", argv[1])) if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix); return cmd_parseopt(argc - 1, argv + 1, prefix);
@ -596,6 +598,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
} }
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) { if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
quiet = 1; quiet = 1;
flags |= GET_SHA1_QUIETLY;
continue; continue;
} }
if (!strcmp(arg, "--short") || if (!strcmp(arg, "--short") ||
@ -818,7 +821,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
name++; name++;
type = REVERSED; type = REVERSED;
} }
if (!get_sha1(name, sha1)) { if (!get_sha1_with_context(name, flags, sha1, &unused)) {
if (verify) if (verify)
revs_count++; revs_count++;
else else

View File

@ -723,6 +723,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
char nth_desc[256]; char nth_desc[256];
char *ref; char *ref;
int base = 0; int base = 0;
unsigned int flags = 0;
if (ac == 0) { if (ac == 0) {
static const char *fake_av[2]; static const char *fake_av[2];
@ -749,7 +750,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
/* Ah, that is a date spec... */ /* Ah, that is a date spec... */
unsigned long at; unsigned long at;
at = approxidate(reflog_base); at = approxidate(reflog_base);
read_ref_at(ref, at, -1, sha1, NULL, read_ref_at(ref, flags, at, -1, sha1, NULL,
NULL, NULL, &base); NULL, NULL, &base);
} }
} }
@ -760,7 +761,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
unsigned long timestamp; unsigned long timestamp;
int tz; int tz;
if (read_ref_at(ref, 0, base+i, sha1, &logmsg, if (read_ref_at(ref, flags, 0, base+i, sha1, &logmsg,
&timestamp, &tz, NULL)) { &timestamp, &tz, NULL)) {
reflog = i; reflog = i;
break; break;

View File

@ -50,7 +50,7 @@ clear_stash () {
then then
die "$(gettext "git stash clear with parameters is unimplemented")" die "$(gettext "git stash clear with parameters is unimplemented")"
fi fi
if current=$(git rev-parse --verify $ref_stash 2>/dev/null) if current=$(git rev-parse --verify --quiet $ref_stash)
then then
git update-ref -d $ref_stash $current git update-ref -d $ref_stash $current
fi fi
@ -292,7 +292,7 @@ save_stash () {
} }
have_stash () { have_stash () {
git rev-parse --verify $ref_stash >/dev/null 2>&1 git rev-parse --verify --quiet $ref_stash >/dev/null
} }
list_stash () { list_stash () {
@ -392,12 +392,12 @@ parse_flags_and_rev()
;; ;;
esac esac
REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || { REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
reference="$1" reference="$1"
die "$(eval_gettext "\$reference is not a valid reference")" die "$(eval_gettext "\$reference is not a valid reference")"
} }
i_commit=$(git rev-parse --quiet --verify "$REV^2" 2>/dev/null) && i_commit=$(git rev-parse --verify --quiet "$REV^2") &&
set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) && set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) &&
s=$1 && s=$1 &&
w_commit=$1 && w_commit=$1 &&
@ -409,7 +409,7 @@ parse_flags_and_rev()
test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
IS_STASH_REF=t IS_STASH_REF=t
u_commit=$(git rev-parse --quiet --verify "$REV^3" 2>/dev/null) && u_commit=$(git rev-parse --verify --quiet "$REV^3") &&
u_tree=$(git rev-parse "$REV^3:" 2>/dev/null) u_tree=$(git rev-parse "$REV^3:" 2>/dev/null)
} }
@ -531,7 +531,8 @@ drop_stash () {
die "$(eval_gettext "\${REV}: Could not drop stash entry")" die "$(eval_gettext "\${REV}: Could not drop stash entry")"
# clear_stash if we just dropped the last 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 git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
clear_stash
} }
apply_to_branch () { apply_to_branch () {

8
refs.c
View File

@ -3159,7 +3159,7 @@ static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,
return 1; return 1;
} }
int read_ref_at(const char *refname, unsigned long at_time, int cnt, int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,
unsigned char *sha1, char **msg, unsigned char *sha1, char **msg,
unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt) unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
{ {
@ -3177,8 +3177,12 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb); for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
if (!cb.reccnt) if (!cb.reccnt) {
if (flags & GET_SHA1_QUIETLY)
exit(128);
else
die("Log for %s is empty.", refname); die("Log for %s is empty.", refname);
}
if (cb.found_it) if (cb.found_it)
return 0; return 0;

3
refs.h
View File

@ -206,7 +206,8 @@ extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, cons
int log_ref_setup(const char *refname, char *logfile, int bufsize); int log_ref_setup(const char *refname, char *logfile, int bufsize);
/** Reads log for the value of ref during at_time. **/ /** Reads log for the value of ref during at_time. **/
extern int read_ref_at(const char *refname, unsigned long at_time, int cnt, extern int read_ref_at(const char *refname, unsigned int flags,
unsigned long at_time, int cnt,
unsigned char *sha1, char **msg, unsigned char *sha1, char **msg,
unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt); unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);

View File

@ -432,7 +432,8 @@ static inline int upstream_mark(const char *string, int len)
static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags); static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf); static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
static int get_sha1_basic(const char *str, int len, unsigned char *sha1) static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
unsigned int flags)
{ {
static const char *warn_msg = "refname '%.*s' is ambiguous."; static const char *warn_msg = "refname '%.*s' is ambiguous.";
static const char *object_name_msg = N_( static const char *object_name_msg = N_(
@ -511,7 +512,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (!refs_found) if (!refs_found)
return -1; return -1;
if (warn_ambiguous_refs && if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
(refs_found > 1 || (refs_found > 1 ||
!get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY))) !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
warning(warn_msg, len, str); warning(warn_msg, len, str);
@ -545,7 +546,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
return -1; return -1;
} }
} }
if (read_ref_at(real_ref, at_time, nth, sha1, NULL, if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
&co_time, &co_tz, &co_cnt)) { &co_time, &co_tz, &co_cnt)) {
if (!len) { if (!len) {
if (starts_with(real_ref, "refs/heads/")) { if (starts_with(real_ref, "refs/heads/")) {
@ -557,11 +558,16 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
len = 4; len = 4;
} }
} }
if (at_time) if (at_time) {
if (!(flags & GET_SHA1_QUIETLY)) {
warning("Log for '%.*s' only goes " warning("Log for '%.*s' only goes "
"back to %s.", len, str, "back to %s.", len, str,
show_date(co_time, co_tz, DATE_RFC2822)); show_date(co_time, co_tz, DATE_RFC2822));
else { }
} else {
if (flags & GET_SHA1_QUIETLY) {
exit(128);
}
die("Log for '%.*s' only has %d entries.", die("Log for '%.*s' only has %d entries.",
len, str, co_cnt); len, str, co_cnt);
} }
@ -801,7 +807,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
if (!ret) if (!ret)
return 0; return 0;
ret = get_sha1_basic(name, len, sha1); ret = get_sha1_basic(name, len, sha1, lookup_flags);
if (!ret) if (!ret)
return 0; return 0;

View File

@ -72,15 +72,42 @@ test_expect_success 'fails with any bad rev or many good revs' '
test_expect_success 'fails silently when using -q' ' test_expect_success 'fails silently when using -q' '
test_must_fail git rev-parse --verify --quiet 2>error && test_must_fail git rev-parse --verify --quiet 2>error &&
test -z "$(cat error)" && test_must_be_empty error &&
test_must_fail git rev-parse -q --verify foo 2>error && test_must_fail git rev-parse -q --verify foo 2>error &&
test -z "$(cat error)" && test_must_be_empty error &&
test_must_fail git rev-parse --verify -q HEAD bar 2>error && test_must_fail git rev-parse --verify -q HEAD bar 2>error &&
test -z "$(cat error)" && test_must_be_empty error &&
test_must_fail git rev-parse --quiet --verify baz HEAD 2>error && test_must_fail git rev-parse --quiet --verify baz HEAD 2>error &&
test -z "$(cat error)" && test_must_be_empty error &&
test_must_fail git rev-parse -q --verify $HASH2 HEAD 2>error && test_must_fail git rev-parse -q --verify $HASH2 HEAD 2>error &&
test -z "$(cat error)" test_must_be_empty error
'
test_expect_success 'fails silently when using -q with deleted reflogs' '
ref=$(git rev-parse HEAD) &&
: >.git/logs/refs/test &&
git update-ref -m "message for refs/test" refs/test "$ref" &&
git reflog delete --updateref --rewrite refs/test@{0} &&
test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 &&
test_must_be_empty error
'
test_expect_success 'fails silently when using -q with not enough reflogs' '
ref=$(git rev-parse HEAD) &&
: >.git/logs/refs/test2 &&
git update-ref -m "message for refs/test2" refs/test2 "$ref" &&
test_must_fail git rev-parse -q --verify refs/test2@{999} >error 2>&1 &&
test_must_be_empty error
'
test_expect_success 'succeeds silently with -q and reflogs that do not go far back enough in time' '
ref=$(git rev-parse HEAD) &&
: >.git/logs/refs/test3 &&
git update-ref -m "message for refs/test3" refs/test3 "$ref" &&
git rev-parse -q --verify refs/test3@{1.year.ago} >actual 2>error &&
test_must_be_empty error &&
echo "$ref" >expect &&
test_cmp expect actual
' '
test_expect_success 'no stdout output on error' ' test_expect_success 'no stdout output on error' '