sequencer: use argv_array_pushf
[gitweb.git] / builtin / commit.c
index a25661f34349f714966c62cd087e357badaefa7c..5e2221c8e8c842314cb177d55223e87328b3da26 100644 (file)
@@ -526,10 +526,29 @@ static int sane_ident_split(struct ident_split *person)
        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");
@@ -574,8 +593,12 @@ static void determine_author_info(struct strbuf *author_ident)
                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)) {
@@ -597,6 +620,36 @@ static int author_date_is_interesting(void)
        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,
                             struct commit *current_head,
                             struct wt_status *s,
@@ -653,9 +706,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        } else if (use_message) {
                char *buffer;
                buffer = strstr(use_message_buffer, "\n\n");
-               if (!use_editor && (!buffer || buffer[2] == '\0'))
-                       die(_("commit has empty message"));
-               strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+               if (buffer)
+                       strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
                hook_arg1 = "commit";
                hook_arg2 = use_message;
        } else if (fixup_message) {
@@ -751,6 +803,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        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 */
@@ -826,7 +880,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                (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;
@@ -844,8 +898,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 
                if (get_sha1(parent, sha1))
                        commitable = !!active_nr;
-               else
-                       commitable = index_differs_from(parent, 0);
+               else {
+                       /*
+                        * Unless the user did explicitly request a submodule
+                        * ignore mode by passing a command line option we do
+                        * not ignore any changed submodule SHA-1s when
+                        * comparing index and parent, no matter what is
+                        * configured. Otherwise we won't commit any
+                        * submodules which were manually staged, which would
+                        * be really confusing.
+                        */
+                       int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+                       if (ignore_submodule_arg &&
+                           !strcmp(ignore_submodule_arg, "all"))
+                               diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
+                       commitable = index_differs_from(parent, diff_flags);
+               }
        }
        strbuf_release(&committer_ident);
 
@@ -1690,6 +1758,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                                           ? 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)
@@ -1699,10 +1771,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        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"));