Merge branch 'da/rev-parse-verify-quiet'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 Sep 2014 19:36:10 +0000 (12:36 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 Sep 2014 19:36:10 +0000 (12:36 -0700)
"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

1  2 
builtin/show-branch.c
git-stash.sh
refs.c
refs.h
diff --combined builtin/show-branch.c
index a1275237ee19473e18397e94868d24d52231d1c3,46498e111354bf0d86bb04f5207812e7f54259d8..199b081e9b805cceb1f2097f2d33966e5f8ff167
@@@ -563,7 -563,7 +563,7 @@@ static int git_show_branch_config(cons
                        default_arg[default_num++] = "show-branch";
                } else if (default_alloc <= default_num + 1) {
                        default_alloc = default_alloc * 3 / 2 + 20;
 -                      default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
 +                      REALLOC_ARRAY(default_arg, default_alloc);
                }
                default_arg[default_num++] = xstrdup(value);
                default_arg[default_num] = NULL;
@@@ -723,6 -723,7 +723,7 @@@ int cmd_show_branch(int ac, const char 
                char nth_desc[256];
                char *ref;
                int base = 0;
+               unsigned int flags = 0;
  
                if (ac == 0) {
                        static const char *fake_av[2];
                                /* Ah, that is a date spec... */
                                unsigned long at;
                                at = approxidate(reflog_base);
-                               read_ref_at(ref, at, -1, sha1, NULL,
+                               read_ref_at(ref, flags, at, -1, sha1, NULL,
                                            NULL, NULL, &base);
                        }
                }
                        unsigned long timestamp;
                        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)) {
                                reflog = i;
                                break;
diff --combined git-stash.sh
index 0158c7338685c8ccbc31766927f905b455a444c2,7ece0f1420e019b517088abdd828ff73c6b13ec0..d4cf818be9488f1b94fdf4766a8f73db6bfd1029
@@@ -50,7 -50,7 +50,7 @@@ clear_stash () 
        then
                die "$(gettext "git stash clear with parameters is unimplemented")"
        fi
-       if current=$(git rev-parse --verify $ref_stash 2>/dev/null)
+       if current=$(git rev-parse --verify --quiet $ref_stash)
        then
                git update-ref -d $ref_stash $current
        fi
@@@ -292,7 -292,7 +292,7 @@@ save_stash () 
  }
  
  have_stash () {
-       git rev-parse --verify $ref_stash >/dev/null 2>&1
+       git rev-parse --verify --quiet $ref_stash >/dev/null
  }
  
  list_stash () {
@@@ -392,12 -392,12 +392,12 @@@ parse_flags_and_rev(
                ;;
        esac
  
-       REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || {
+       REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
                reference="$1"
 -              die "$(eval_gettext "\$reference is not valid reference")"
 +              die "$(eval_gettext "\$reference is not 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) &&
        s=$1 &&
        w_commit=$1 &&
        test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
        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)
  }
  
@@@ -531,7 -531,8 +531,8 @@@ drop_stash () 
                die "$(eval_gettext "\${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
+       git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
+       clear_stash
  }
  
  apply_to_branch () {
diff --combined refs.c
index 311a6b52b1a9b65c997357e2d1d80e0e4743b2ca,9e405f9e41ae52c413d4feb29521e30948a81ca8..ffd45e92922ec52dccccfaecf1ceaf29f9231337
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -784,32 -784,37 +784,32 @@@ static void prime_ref_dir(struct ref_di
                        prime_ref_dir(get_ref_dir(entry));
        }
  }
 -/*
 - * Return true iff refname1 and refname2 conflict with each other.
 - * Two reference names conflict if one of them exactly matches the
 - * leading components of the other; e.g., "foo/bar" conflicts with
 - * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
 - * "foo/barbados".
 - */
 -static int names_conflict(const char *refname1, const char *refname2)
 +
 +static int entry_matches(struct ref_entry *entry, const char *refname)
  {
 -      for (; *refname1 && *refname1 == *refname2; refname1++, refname2++)
 -              ;
 -      return (*refname1 == '\0' && *refname2 == '/')
 -              || (*refname1 == '/' && *refname2 == '\0');
 +      return refname && !strcmp(entry->name, refname);
  }
  
 -struct name_conflict_cb {
 -      const char *refname;
 -      const char *oldrefname;
 -      const char *conflicting_refname;
 +struct nonmatching_ref_data {
 +      const char *skip;
 +      struct ref_entry *found;
  };
  
 -static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
 +static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)
  {
 -      struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
 -      if (data->oldrefname && !strcmp(data->oldrefname, entry->name))
 +      struct nonmatching_ref_data *data = vdata;
 +
 +      if (entry_matches(entry, data->skip))
                return 0;
 -      if (names_conflict(data->refname, entry->name)) {
 -              data->conflicting_refname = entry->name;
 -              return 1;
 -      }
 -      return 0;
 +
 +      data->found = entry;
 +      return 1;
 +}
 +
 +static void report_refname_conflict(struct ref_entry *entry,
 +                                  const char *refname)
 +{
 +      error("'%s' exists; cannot create '%s'", entry->name, refname);
  }
  
  /*
   * oldrefname is non-NULL, ignore potential conflicts with oldrefname
   * (e.g., because oldrefname is scheduled for deletion in the same
   * operation).
 + *
 + * Two reference names conflict if one of them exactly matches the
 + * leading components of the other; e.g., "foo/bar" conflicts with
 + * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
 + * "foo/barbados".
   */
  static int is_refname_available(const char *refname, const char *oldrefname,
                                struct ref_dir *dir)
  {
 -      struct name_conflict_cb data;
 -      data.refname = refname;
 -      data.oldrefname = oldrefname;
 -      data.conflicting_refname = NULL;
 +      const char *slash;
 +      size_t len;
 +      int pos;
 +      char *dirname;
  
 -      sort_ref_dir(dir);
 -      if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, &data)) {
 -              error("'%s' exists; cannot create '%s'",
 -                    data.conflicting_refname, refname);
 +      for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
 +              /*
 +               * We are still at a leading dir of the refname; we are
 +               * looking for a conflict with a leaf entry.
 +               *
 +               * If we find one, we still must make sure it is
 +               * not "oldrefname".
 +               */
 +              pos = search_ref_dir(dir, refname, slash - refname);
 +              if (pos >= 0) {
 +                      struct ref_entry *entry = dir->entries[pos];
 +                      if (entry_matches(entry, oldrefname))
 +                              return 1;
 +                      report_refname_conflict(entry, refname);
 +                      return 0;
 +              }
 +
 +
 +              /*
 +               * Otherwise, we can try to continue our search with
 +               * the next component; if we come up empty, we know
 +               * there is nothing under this whole prefix.
 +               */
 +              pos = search_ref_dir(dir, refname, slash + 1 - refname);
 +              if (pos < 0)
 +                      return 1;
 +
 +              dir = get_ref_dir(dir->entries[pos]);
 +      }
 +
 +      /*
 +       * We are at the leaf of our refname; we want to
 +       * make sure there are no directories which match it.
 +       */
 +      len = strlen(refname);
 +      dirname = xmallocz(len + 1);
 +      sprintf(dirname, "%s/", refname);
 +      pos = search_ref_dir(dir, dirname, len + 1);
 +      free(dirname);
 +
 +      if (pos >= 0) {
 +              /*
 +               * We found a directory named "refname". It is a
 +               * problem iff it contains any ref that is not
 +               * "oldrefname".
 +               */
 +              struct ref_entry *entry = dir->entries[pos];
 +              struct ref_dir *dir = get_ref_dir(entry);
 +              struct nonmatching_ref_data data;
 +
 +              data.skip = oldrefname;
 +              sort_ref_dir(dir);
 +              if (!do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data))
 +                      return 1;
 +
 +              report_refname_conflict(data.found, refname);
                return 0;
        }
 +
 +      /*
 +       * There is no point in searching for another leaf
 +       * node which matches it; such an entry would be the
 +       * ref we are looking for, not a conflict.
 +       */
        return 1;
  }
  
@@@ -2248,12 -2190,25 +2248,12 @@@ struct ref_lock *lock_any_ref_for_updat
   * Write an entry to the packed-refs file for the specified refname.
   * If peeled is non-NULL, write it as the entry's peeled value.
   */
 -static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
 +static void write_packed_entry(FILE *fh, char *refname, unsigned char *sha1,
                               unsigned char *peeled)
  {
 -      char line[PATH_MAX + 100];
 -      int len;
 -
 -      len = snprintf(line, sizeof(line), "%s %s\n",
 -                     sha1_to_hex(sha1), refname);
 -      /* this should not happen but just being defensive */
 -      if (len > sizeof(line))
 -              die("too long a refname '%s'", refname);
 -      write_or_die(fd, line, len);
 -
 -      if (peeled) {
 -              if (snprintf(line, sizeof(line), "^%s\n",
 -                           sha1_to_hex(peeled)) != PEELED_LINE_LENGTH)
 -                      die("internal error");
 -              write_or_die(fd, line, PEELED_LINE_LENGTH);
 -      }
 +      fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
 +      if (peeled)
 +              fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
  }
  
  /*
   */
  static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
  {
 -      int *fd = cb_data;
        enum peel_status peel_status = peel_entry(entry, 0);
  
        if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
                error("internal error: %s is not a valid packed reference!",
                      entry->name);
 -      write_packed_entry(*fd, entry->name, entry->u.value.sha1,
 +      write_packed_entry(cb_data, entry->name, entry->u.value.sha1,
                           peel_status == PEEL_PEELED ?
                           entry->u.value.peeled : NULL);
        return 0;
@@@ -2302,22 -2258,15 +2302,22 @@@ int commit_packed_refs(void
                get_packed_ref_cache(&ref_cache);
        int error = 0;
        int save_errno = 0;
 +      FILE *out;
  
        if (!packed_ref_cache->lock)
                die("internal error: packed-refs not locked");
 -      write_or_die(packed_ref_cache->lock->fd,
 -                   PACKED_REFS_HEADER, strlen(PACKED_REFS_HEADER));
  
 +      out = fdopen(packed_ref_cache->lock->fd, "w");
 +      if (!out)
 +              die_errno("unable to fdopen packed-refs descriptor");
 +
 +      fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
        do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
 -                               0, write_packed_entry_fn,
 -                               &packed_ref_cache->lock->fd);
 +                               0, write_packed_entry_fn, out);
 +      if (fclose(out))
 +              die_errno("write error");
 +      packed_ref_cache->lock->fd = -1;
 +
        if (commit_lock_file(packed_ref_cache->lock)) {
                save_errno = errno;
                error = -1;
@@@ -3159,7 -3108,7 +3159,7 @@@ static int read_ref_at_ent_oldest(unsig
        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 long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
  {
  
        for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
  
-       if (!cb.reccnt)
-               die("Log for %s is empty.", refname);
+       if (!cb.reccnt) {
+               if (flags & GET_SHA1_QUIETLY)
+                       exit(128);
+               else
+                       die("Log for %s is empty.", refname);
+       }
        if (cb.found_it)
                return 0;
  
diff --combined refs.h
index 10fc3a2634409571d38a1322b9853547d216945b,0ca60599b1a321b2805df669a4f50a1c8e58cb19..2328f06e77d34d76a1f4affedcca2c51ff9e0093
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -109,7 -109,7 +109,7 @@@ static inline const char *has_glob_spec
  extern int for_each_rawref(each_ref_fn, void *);
  
  extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
 -extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_listrefnames);
 +extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames);
  
  /*
   * Lock the packed-refs file for writing.  Flags is passed to
@@@ -206,7 -206,8 +206,8 @@@ extern int write_ref_sha1(struct ref_lo
  int log_ref_setup(const char *refname, char *logfile, int bufsize);
  
  /** 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 long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);