Merge branch 'sb/prepare-revision-walk-error-check'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:03 +0000 (12:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:03 +0000 (12:54 -0700)
* sb/prepare-revision-walk-error-check:
prepare_revision_walk(): check for return value in all places

1  2 
builtin/branch.c
builtin/commit.c
remote.c
diff --combined builtin/branch.c
index 0591b22a483619ac9a7d889a49e45ffa9d68ab72,e91ecc6fbd2f9e3966997c6e8fec0a5488f740fb..ced422b627fc05c462f6be8b6c20ee0ba9ff2628
@@@ -294,13 -294,13 +294,13 @@@ static char *resolve_symref(const char 
  {
        unsigned char sha1[20];
        int flag;
 -      const char *dst, *cp;
 +      const char *dst;
  
        dst = resolve_ref_unsafe(src, sha1, 0, &flag);
        if (!(dst && (flag & REF_ISSYMREF)))
                return NULL;
 -      if (prefix && (cp = skip_prefix(dst, prefix)))
 -              dst = cp;
 +      if (prefix)
 +              skip_prefix(dst, prefix, &dst);
        return xstrdup(dst);
  }
  
@@@ -653,7 -653,9 +653,9 @@@ static int print_ref_list(int kinds, in
                add_pending_object(&ref_list.revs,
                                   (struct object *) filter, "");
                ref_list.revs.limited = 1;
-               prepare_revision_walk(&ref_list.revs);
+               if (prepare_revision_walk(&ref_list.revs))
+                       die(_("revision walk setup failed"));
                if (verbose)
                        ref_list.maxwidth = calc_maxwidth(&ref_list);
        }
diff --combined builtin/commit.c
index a3eaf4b5eac72aecc7deb4e9c564e98505b74bfb,447ded63fd09b346ae5c1a0c6008dd196d6fd99e..36e3a2eef2b65e1e9977fd66e5bd514e492c3e56
@@@ -42,20 -42,7 +42,20 @@@ static const char * const builtin_statu
        NULL
  };
  
 -static const char implicit_ident_advice[] =
 +static const char implicit_ident_advice_noconfig[] =
 +N_("Your name and email address were configured automatically based\n"
 +"on your username and hostname. Please check that they are accurate.\n"
 +"You can suppress this message by setting them explicitly. Run the\n"
 +"following command and follow the instructions in your editor to edit\n"
 +"your configuration file:\n"
 +"\n"
 +"    git config --global --edit\n"
 +"\n"
 +"After doing this, you may fix the identity used for this commit with:\n"
 +"\n"
 +"    git commit --amend --reset-author\n");
 +
 +static const char implicit_ident_advice_config[] =
  N_("Your name and email address were configured automatically based\n"
  "on your username and hostname. Please check that they are accurate.\n"
  "You can suppress this message by setting them explicitly:\n"
@@@ -318,6 -305,7 +318,6 @@@ static void refresh_cache_or_die(int re
  static char *prepare_index(int argc, const char **argv, const char *prefix,
                           const struct commit *current_head, int is_status)
  {
 -      int fd;
        struct string_list partial;
        struct pathspec pathspec;
        int refresh_flags = REFRESH_QUIET;
  
        if (interactive) {
                char *old_index_env = NULL;
 -              fd = hold_locked_index(&index_lock, 1);
 +              hold_locked_index(&index_lock, 1);
  
                refresh_cache_or_die(refresh_flags);
  
 -              if (write_cache(fd, active_cache, active_nr) ||
 -                  close_lock_file(&index_lock))
 +              if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to create temporary index"));
  
                old_index_env = getenv(INDEX_ENVIRONMENT);
         * (B) on failure, rollback the real index.
         */
        if (all || (also && pathspec.nr)) {
 -              fd = hold_locked_index(&index_lock, 1);
 +              hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
 -              if (write_cache(fd, active_cache, active_nr) ||
 -                  close_lock_file(&index_lock))
 +              if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
                return index_lock.filename;
         * We still need to refresh the index here.
         */
        if (!only && !pathspec.nr) {
 -              fd = hold_locked_index(&index_lock, 1);
 +              hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
                if (active_cache_changed) {
                        update_main_cache_tree(WRITE_TREE_SILENT);
 -                      if (write_cache(fd, active_cache, active_nr) ||
 -                          commit_locked_index(&index_lock))
 +                      if (write_locked_index(&the_index, &index_lock,
 +                                             COMMIT_LOCK))
                                die(_("unable to write new_index file"));
                } else {
                        rollback_lock_file(&index_lock);
                        die(_("cannot do a partial commit during a cherry-pick."));
        }
  
 -      memset(&partial, 0, sizeof(partial));
 -      partial.strdup_strings = 1;
 +      string_list_init(&partial, 1);
        if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
                exit(1);
  
        if (read_cache() < 0)
                die(_("cannot read the index"));
  
 -      fd = hold_locked_index(&index_lock, 1);
 +      hold_locked_index(&index_lock, 1);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
 -      if (write_cache(fd, active_cache, active_nr) ||
 -          close_lock_file(&index_lock))
 +      if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                die(_("unable to write new_index file"));
  
 -      fd = hold_lock_file_for_update(&false_lock,
 -                                     git_path("next-index-%"PRIuMAX,
 -                                              (uintmax_t) getpid()),
 -                                     LOCK_DIE_ON_ERROR);
 +      hold_lock_file_for_update(&false_lock,
 +                                git_path("next-index-%"PRIuMAX,
 +                                         (uintmax_t) getpid()),
 +                                LOCK_DIE_ON_ERROR);
  
        create_base_index(current_head);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
  
 -      if (write_cache(fd, active_cache, active_nr) ||
 -          close_lock_file(&false_lock))
 +      if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))
                die(_("unable to write temporary index file"));
  
        discard_cache();
@@@ -533,29 -526,10 +533,29 @@@ static int sane_ident_split(struct iden
        return 1;
  }
  
 +static int parse_force_date(const char *in, char *out, int len)
 +{
 +      if (len < 1)
 +              return -1;
 +      *out++ = '@';
 +      len--;
 +
 +      if (parse_date(in, out, len) < 0) {
 +              int errors = 0;
 +              unsigned long t = approxidate_careful(in, &errors);
 +              if (errors)
 +                      return -1;
 +              snprintf(out, len, "%lu", t);
 +      }
 +
 +      return 0;
 +}
 +
  static void determine_author_info(struct strbuf *author_ident)
  {
        char *name, *email, *date;
        struct ident_split author;
 +      char date_buf[64];
  
        name = getenv("GIT_AUTHOR_NAME");
        email = getenv("GIT_AUTHOR_EMAIL");
                email = xstrndup(lb + 2, rb - (lb + 2));
        }
  
 -      if (force_date)
 -              date = force_date;
 +      if (force_date) {
 +              if (parse_force_date(force_date, date_buf, sizeof(date_buf)))
 +                      die(_("invalid date format: %s"), force_date);
 +              date = date_buf;
 +      }
 +
        strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
        if (!split_ident_line(&author, author_ident->buf, author_ident->len) &&
            sane_ident_split(&author)) {
        }
  }
  
 -static char *cut_ident_timestamp_part(char *string)
 +static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
 +{
 +      if (split_ident_line(id, buf->buf, buf->len) ||
 +          !sane_ident_split(id))
 +              die(_("Malformed ident string: '%s'"), buf->buf);
 +}
 +
 +static int author_date_is_interesting(void)
  {
 -      char *ket = strrchr(string, '>');
 -      if (!ket || ket[1] != ' ')
 -              die(_("Malformed ident string: '%s'"), string);
 -      *++ket = '\0';
 -      return ket;
 +      return author_message || force_date;
 +}
 +
 +static void adjust_comment_line_char(const struct strbuf *sb)
 +{
 +      char candidates[] = "#;@!$%^&|:";
 +      char *candidate;
 +      const char *p;
 +
 +      comment_line_char = candidates[0];
 +      if (!memchr(sb->buf, comment_line_char, sb->len))
 +              return;
 +
 +      p = sb->buf;
 +      candidate = strchr(candidates, *p);
 +      if (candidate)
 +              *candidate = ' ';
 +      for (p = sb->buf; *p; p++) {
 +              if ((p[0] == '\n' || p[0] == '\r') && p[1]) {
 +                      candidate = strchr(candidates, p[1]);
 +                      if (candidate)
 +                              *candidate = ' ';
 +              }
 +      }
 +
 +      for (p = candidates; *p == ' '; p++)
 +              ;
 +      if (!*p)
 +              die(_("unable to select a comment character that is not used\n"
 +                    "in the current commit message"));
 +      comment_line_char = *p;
  }
  
  static int prepare_to_commit(const char *index_file, const char *prefix,
                char *buffer;
                buffer = strstr(use_message_buffer, "\n\n");
                if (buffer)
 -                      strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
 +                      strbuf_addstr(&sb, buffer + 2);
                hook_arg1 = "commit";
                hook_arg2 = use_message;
        } else if (fixup_message) {
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                die_errno(_("could not write commit template"));
  
 +      if (auto_comment_line_char)
 +              adjust_comment_line_char(&sb);
        strbuf_release(&sb);
  
        /* This checks if committer ident is explicitly given */
        if (use_editor && include_status) {
                int ident_shown = 0;
                int saved_color_setting;
 -              char *ai_tmp, *ci_tmp;
 +              struct ident_split ci, ai;
 +
                if (whence != FROM_COMMIT) {
                        if (cleanup_mode == CLEANUP_SCISSORS)
                                wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                        "%s", only_include_assumed);
  
 -              ai_tmp = cut_ident_timestamp_part(author_ident->buf);
 -              ci_tmp = cut_ident_timestamp_part(committer_ident.buf);
 -              if (strcmp(author_ident->buf, committer_ident.buf))
 +              split_ident_or_die(&ai, author_ident);
 +              split_ident_or_die(&ci, &committer_ident);
 +
 +              if (ident_cmp(&ai, &ci))
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                _("%s"
 -                              "Author:    %s"),
 +                              "Author:    %.*s <%.*s>"),
                                ident_shown++ ? "" : "\n",
 -                              author_ident->buf);
 +                              (int)(ai.name_end - ai.name_begin), ai.name_begin,
 +                              (int)(ai.mail_end - ai.mail_begin), ai.mail_begin);
 +
 +              if (author_date_is_interesting())
 +                      status_printf_ln(s, GIT_COLOR_NORMAL,
 +                              _("%s"
 +                              "Date:      %s"),
 +                              ident_shown++ ? "" : "\n",
 +                              show_ident_date(&ai, DATE_NORMAL));
  
                if (!committer_ident_sufficiently_given())
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                _("%s"
 -                              "Committer: %s"),
 +                              "Committer: %.*s <%.*s>"),
                                ident_shown++ ? "" : "\n",
 -                              committer_ident.buf);
 +                              (int)(ci.name_end - ci.name_begin), ci.name_begin,
 +                              (int)(ci.mail_end - ci.mail_begin), ci.mail_begin);
  
                if (ident_shown)
 -                      status_printf_ln(s, GIT_COLOR_NORMAL, "");
 +                      status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
  
                saved_color_setting = s->use_color;
                s->use_color = 0;
                commitable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
 -
 -              *ai_tmp = ' ';
 -              *ci_tmp = ' ';
        } else {
                unsigned char sha1[20];
                const char *parent = "HEAD";
@@@ -1027,7 -954,7 +1027,7 @@@ static int message_is_empty(struct strb
  static int template_untouched(struct strbuf *sb)
  {
        struct strbuf tmpl = STRBUF_INIT;
 -      char *start;
 +      const char *start;
  
        if (cleanup_mode == CLEANUP_NONE && sb->len)
                return 0;
                return 0;
  
        stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
 -      start = (char *)skip_prefix(sb->buf, tmpl.buf);
 -      if (!start)
 +      if (!skip_prefix(sb->buf, tmpl.buf, &start))
                start = sb->buf;
        strbuf_release(&tmpl);
        return rest_is_empty(sb, start - sb->buf);
@@@ -1061,7 -989,8 +1061,8 @@@ static const char *find_author_by_nickn
        revs.mailmap = &mailmap;
        read_mailmap(revs.mailmap, NULL);
  
-       prepare_revision_walk(&revs);
+       if (prepare_revision_walk(&revs))
+               die(_("revision walk setup failed"));
        commit = get_revision(&revs);
        if (commit) {
                struct pretty_print_context ctx = {0};
@@@ -1415,24 -1344,6 +1416,24 @@@ int cmd_status(int argc, const char **a
        return 0;
  }
  
 +static const char *implicit_ident_advice(void)
 +{
 +      char *user_config = NULL;
 +      char *xdg_config = NULL;
 +      int config_exists;
 +
 +      home_config_paths(&user_config, &xdg_config, "config");
 +      config_exists = file_exists(user_config) || file_exists(xdg_config);
 +      free(user_config);
 +      free(xdg_config);
 +
 +      if (config_exists)
 +              return _(implicit_ident_advice_config);
 +      else
 +              return _(implicit_ident_advice_noconfig);
 +
 +}
 +
  static void print_summary(const char *prefix, const unsigned char *sha1,
                          int initial_commit)
  {
                strbuf_addstr(&format, "\n Author: ");
                strbuf_addbuf_percentquote(&format, &author_ident);
        }
 +      if (author_date_is_interesting()) {
 +              struct strbuf date = STRBUF_INIT;
 +              format_commit_message(commit, "%ad", &date, &pctx);
 +              strbuf_addstr(&format, "\n Date: ");
 +              strbuf_addbuf_percentquote(&format, &date);
 +              strbuf_release(&date);
 +      }
        if (!committer_ident_sufficiently_given()) {
                strbuf_addstr(&format, "\n Committer: ");
                strbuf_addbuf_percentquote(&format, &committer_ident);
                if (advice_implicit_identity) {
                        strbuf_addch(&format, '\n');
 -                      strbuf_addstr(&format, _(implicit_ident_advice));
 +                      strbuf_addstr(&format, implicit_ident_advice());
                }
        }
        strbuf_release(&author_ident);
@@@ -1782,10 -1686,6 +1783,10 @@@ int cmd_commit(int argc, const char **a
                                           ? NULL
                                           : current_head->object.sha1,
                                           0, NULL);
 +      if (!ref_lock) {
 +              rollback_index_files();
 +              die(_("cannot lock HEAD ref"));
 +      }
  
        nl = strchr(sb.buf, '\n');
        if (nl)
        strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
        strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
  
 -      if (!ref_lock) {
 -              rollback_index_files();
 -              die(_("cannot lock HEAD ref"));
 -      }
        if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
                rollback_index_files();
                die(_("cannot update HEAD ref"));
diff --combined remote.c
index 0e39b2442d90db07b2ad53069af2263b15472870,dc0c427968e534c74bd853b12e261c529f1f9588..35e62ee0f55cf6c44c0ad94761249ef12b7c19c5
+++ b/remote.c
@@@ -42,7 -42,6 +42,7 @@@ struct rewrites 
  static struct remote **remotes;
  static int remotes_alloc;
  static int remotes_nr;
 +static struct hashmap remotes_hash;
  
  static struct branch **branches;
  static int branches_alloc;
@@@ -137,51 -136,26 +137,51 @@@ static void add_url_alias(struct remot
        add_pushurl_alias(remote, url);
  }
  
 +struct remotes_hash_key {
 +      const char *str;
 +      int len;
 +};
 +
 +static int remotes_hash_cmp(const struct remote *a, const struct remote *b, const struct remotes_hash_key *key)
 +{
 +      if (key)
 +              return strncmp(a->name, key->str, key->len) || a->name[key->len];
 +      else
 +              return strcmp(a->name, b->name);
 +}
 +
 +static inline void init_remotes_hash(void)
 +{
 +      if (!remotes_hash.cmpfn)
 +              hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, 0);
 +}
 +
  static struct remote *make_remote(const char *name, int len)
  {
 -      struct remote *ret;
 -      int i;
 +      struct remote *ret, *replaced;
 +      struct remotes_hash_key lookup;
 +      struct hashmap_entry lookup_entry;
  
 -      for (i = 0; i < remotes_nr; i++) {
 -              if (len ? (!strncmp(name, remotes[i]->name, len) &&
 -                         !remotes[i]->name[len]) :
 -                  !strcmp(name, remotes[i]->name))
 -                      return remotes[i];
 -      }
 +      if (!len)
 +              len = strlen(name);
 +
 +      init_remotes_hash();
 +      lookup.str = name;
 +      lookup.len = len;
 +      hashmap_entry_init(&lookup_entry, memhash(name, len));
 +
 +      if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)
 +              return ret;
  
        ret = xcalloc(1, sizeof(struct remote));
        ret->prune = -1;  /* unspecified */
        ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
        remotes[remotes_nr++] = ret;
 -      if (len)
 -              ret->name = xstrndup(name, len);
 -      else
 -              ret->name = xstrdup(name);
 +      ret->name = xstrndup(name, len);
 +
 +      hashmap_entry_init(ret, lookup_entry.hash);
 +      replaced = hashmap_put(&remotes_hash, ret);
 +      assert(replaced == NULL);  /* no previous entry overwritten */
        return ret;
  }
  
@@@ -196,6 -170,7 +196,6 @@@ static struct branch *make_branch(cons
  {
        struct branch *ret;
        int i;
 -      char *refname;
  
        for (i = 0; i < branches_nr; i++) {
                if (len ? (!strncmp(name, branches[i]->name, len) &&
                ret->name = xstrndup(name, len);
        else
                ret->name = xstrdup(name);
 -      refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1);
 -      strcpy(refname, "refs/heads/");
 -      strcpy(refname + strlen("refs/heads/"), ret->name);
 -      ret->refname = refname;
 +      ret->refname = xstrfmt("refs/heads/%s", ret->name);
  
        return ret;
  }
@@@ -510,8 -488,9 +510,8 @@@ static void read_config(void
        current_branch = NULL;
        head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
        if (head_ref && (flag & REF_ISSYMREF) &&
 -          starts_with(head_ref, "refs/heads/")) {
 -              current_branch =
 -                      make_branch(head_ref + strlen("refs/heads/"), 0);
 +          skip_prefix(head_ref, "refs/heads/", &head_ref)) {
 +              current_branch = make_branch(head_ref, 0);
        }
        git_config(handle_config, NULL);
        if (branch_pushremote_name) {
@@@ -743,16 -722,13 +743,16 @@@ struct remote *pushremote_get(const cha
  
  int remote_is_configured(const char *name)
  {
 -      int i;
 +      struct remotes_hash_key lookup;
 +      struct hashmap_entry lookup_entry;
        read_config();
  
 -      for (i = 0; i < remotes_nr; i++)
 -              if (!strcmp(name, remotes[i]->name))
 -                      return 1;
 -      return 0;
 +      init_remotes_hash();
 +      lookup.str = name;
 +      lookup.len = strlen(name);
 +      hashmap_entry_init(&lookup_entry, memhash(name, lookup.len));
 +
 +      return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL;
  }
  
  int for_each_remote(each_remote_fn fn, void *priv)
@@@ -1218,7 -1194,7 +1218,7 @@@ static int match_explicit(struct ref *s
        case 1:
                break;
        case 0:
 -              if (!memcmp(dst_value, "refs/", 5))
 +              if (starts_with(dst_value, "refs/"))
                        matched_dst = make_linked_ref(dst_value, dst_tail);
                else if (is_null_sha1(matched_src->new_sha1))
                        error("unable to delete '%s': remote ref does not exist",
@@@ -1922,7 -1898,8 +1922,8 @@@ int stat_tracking_info(struct branch *b
  
        init_revisions(&revs, NULL);
        setup_revisions(rev_argc, rev_argv, &revs, NULL);
-       prepare_revision_walk(&revs);
+       if (prepare_revision_walk(&revs))
+               die("revision walk setup failed");
  
        /* ... and count the commits on each side. */
        *num_ours = 0;
  int format_tracking_info(struct branch *branch, struct strbuf *sb)
  {
        int ours, theirs;
 -      const char *base;
 +      char *base;
        int upstream_is_gone = 0;
  
        switch (stat_tracking_info(branch, &ours, &theirs)) {
                break;
        }
  
 -      base = branch->merge[0]->dst;
 -      base = shorten_unambiguous_ref(base, 0);
 +      base = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
        if (upstream_is_gone) {
                strbuf_addf(sb,
                        _("Your branch is based on '%s', but the upstream is gone.\n"),
                        strbuf_addf(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
        }
 +      free(base);
        return 1;
  }