describe: Make --tags and --all match lightweight tags more often
[gitweb.git] / builtin-commit.c
index 8165bb3d31c6cdd92c83663c5dd081e564dcfc1e..a2755dc3befeb5ed768f692ee58e5147ad933e26 100644 (file)
@@ -448,7 +448,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
 {
        struct stat statbuf;
        int commitable, saved_color_setting;
-       struct strbuf sb;
+       struct strbuf sb = STRBUF_INIT;
        char *buffer;
        FILE *fp;
        const char *hook_arg1 = NULL;
@@ -458,7 +458,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
        if (!no_verify && run_hook(index_file, "pre-commit", NULL))
                return 0;
 
-       strbuf_init(&sb, 0);
        if (message.len) {
                strbuf_addbuf(&sb, &message);
                hook_arg1 = "message";
@@ -511,10 +510,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
                stripspace(&sb, 0);
 
        if (signoff) {
-               struct strbuf sob;
+               struct strbuf sob = STRBUF_INIT;
                int i;
 
-               strbuf_init(&sob, 0);
                strbuf_addstr(&sob, sign_off_header);
                strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
                                             getenv("GIT_COMMITTER_EMAIL")));
@@ -639,7 +637,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
                active_cache_tree = cache_tree();
        if (cache_tree_update(active_cache_tree,
                              active_cache, active_nr, 0, 0) < 0) {
-               error("Error building trees");
+               error("Error building trees; the index is unmerged?");
                return 0;
        }
 
@@ -667,20 +665,19 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
 }
 
 /*
- * Find out if the message starting at position 'start' in the strbuf
- * contains only whitespace and Signed-off-by lines.
+ * Find out if the message in the strbuf contains only whitespace and
+ * Signed-off-by lines.
  */
-static int message_is_empty(struct strbuf *sb, int start)
+static int message_is_empty(struct strbuf *sb)
 {
-       struct strbuf tmpl;
+       struct strbuf tmpl = STRBUF_INIT;
        const char *nl;
-       int eol, i;
+       int eol, i, start = 0;
 
        if (cleanup_mode == CLEANUP_NONE && sb->len)
                return 0;
 
        /* See if the template is just a prefix of the message. */
-       strbuf_init(&tmpl, 0);
        if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
                stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
                if (start + tmpl.len <= sb->len &&
@@ -929,34 +926,14 @@ static const char commit_utf8_warn[] =
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n";
 
-static void add_parent(struct strbuf *sb, const unsigned char *sha1)
-{
-       struct object *obj = parse_object(sha1);
-       const char *parent = sha1_to_hex(sha1);
-       const char *cp;
-
-       if (!obj)
-               die("Unable to find commit parent %s", parent);
-       if (obj->type != OBJ_COMMIT)
-               die("Parent %s isn't a proper commit", parent);
-
-       for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) {
-               if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') {
-                       error("duplicate parent %s ignored", parent);
-                       return;
-               }
-       }
-       strbuf_addf(sb, "parent %s\n", parent);
-}
-
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
-       int header_len;
-       struct strbuf sb;
+       struct strbuf sb = STRBUF_INIT;
        const char *index_file, *reflog_msg;
        char *nl, *p;
        unsigned char commit_sha1[20];
        struct ref_lock *ref_lock;
+       struct commit_list *parents = NULL, **pptr = &parents;
 
        git_config(git_commit_config, NULL);
 
@@ -971,13 +948,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                return 1;
        }
 
-       /*
-        * The commit object
-        */
-       strbuf_init(&sb, 0);
-       strbuf_addf(&sb, "tree %s\n",
-                   sha1_to_hex(active_cache_tree->sha1));
-
        /* Determine parents */
        if (initial_commit) {
                reflog_msg = "commit (initial)";
@@ -991,14 +961,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        die("could not parse HEAD commit");
 
                for (c = commit->parents; c; c = c->next)
-                       add_parent(&sb, c->item->object.sha1);
+                       pptr = &commit_list_insert(c->item, pptr)->next;
        } else if (in_merge) {
-               struct strbuf m;
+               struct strbuf m = STRBUF_INIT;
                FILE *fp;
 
                reflog_msg = "commit (merge)";
-               add_parent(&sb, head_sha1);
-               strbuf_init(&m, 0);
+               pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
                fp = fopen(git_path("MERGE_HEAD"), "r");
                if (fp == NULL)
                        die("could not open %s for reading: %s",
@@ -1007,24 +976,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        unsigned char sha1[20];
                        if (get_sha1_hex(m.buf, sha1) < 0)
                                die("Corrupt MERGE_HEAD file (%s)", m.buf);
-                       add_parent(&sb, sha1);
+                       pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next;
                }
                fclose(fp);
                strbuf_release(&m);
        } else {
                reflog_msg = "commit";
-               strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+               pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
        }
-
-       strbuf_addf(&sb, "author %s\n",
-                   fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME));
-       strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
-       if (!is_encoding_utf8(git_commit_encoding))
-               strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
-       strbuf_addch(&sb, '\n');
+       parents = reduce_heads(parents);
 
        /* Finally, get the commit message */
-       header_len = sb.len;
        if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
                rollback_index_files();
                die("could not read commit message");
@@ -1037,16 +999,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        if (cleanup_mode != CLEANUP_NONE)
                stripspace(&sb, cleanup_mode == CLEANUP_ALL);
-       if (sb.len < header_len || message_is_empty(&sb, header_len)) {
+       if (message_is_empty(&sb)) {
                rollback_index_files();
                fprintf(stderr, "Aborting commit due to empty commit message.\n");
                exit(1);
        }
-       strbuf_addch(&sb, '\0');
-       if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
-               fprintf(stderr, commit_utf8_warn);
 
-       if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) {
+       if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
+                       fmt_ident(author_name, author_email, author_date,
+                               IDENT_ERROR_ON_NO_NAME))) {
                rollback_index_files();
                die("failed to write commit object");
        }
@@ -1055,12 +1016,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                                           initial_commit ? NULL : head_sha1,
                                           0);
 
-       nl = strchr(sb.buf + header_len, '\n');
+       nl = strchr(sb.buf, '\n');
        if (nl)
                strbuf_setlen(&sb, nl + 1 - sb.buf);
        else
                strbuf_addch(&sb, '\n');
-       strbuf_remove(&sb, 0, header_len);
        strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
        strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);