mergetool: Provide an empty file when needed
[gitweb.git] / builtin / commit.c
index 776fa81f7484e2bc54651006097f52e0e0f740a8..b9ab5ef3146ff0536cb79dabf8c77605e4974c31 100644 (file)
@@ -62,8 +62,6 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n"
 "Otherwise, please use 'git reset'\n");
 
-static unsigned char head_sha1[20];
-
 static const char *use_message_buffer;
 static const char commit_editmsg[] = "COMMIT_EDITMSG";
 static struct lock_file index_lock; /* real index */
@@ -102,7 +100,7 @@ static enum {
 static char *cleanup_arg;
 
 static enum commit_whence whence;
-static int use_editor = 1, initial_commit, include_status = 1;
+static int use_editor = 1, include_status = 1;
 static int show_ignored_in_status;
 static const char *only_include_assumed;
 static struct strbuf message;
@@ -257,8 +255,9 @@ static int list_paths(struct string_list *list, const char *with_tree,
        m = xcalloc(1, i);
 
        if (with_tree) {
-               const char *max_prefix = pathspec_prefix(prefix, pattern);
-               overlay_tree_on_cache(with_tree, max_prefix);
+               char *max_prefix = common_prefix(pattern);
+               overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);
+               free(max_prefix);
        }
 
        for (i = 0; i < active_nr; i++) {
@@ -296,13 +295,13 @@ static void add_remove_files(struct string_list *list)
        }
 }
 
-static void create_base_index(void)
+static void create_base_index(const struct commit *current_head)
 {
        struct tree *tree;
        struct unpack_trees_options opts;
        struct tree_desc t;
 
-       if (initial_commit) {
+       if (!current_head) {
                discard_cache();
                return;
        }
@@ -315,7 +314,7 @@ static void create_base_index(void)
        opts.dst_index = &the_index;
 
        opts.fn = oneway_merge;
-       tree = parse_tree_indirect(head_sha1);
+       tree = parse_tree_indirect(current_head->object.sha1);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
@@ -334,7 +333,8 @@ static void refresh_cache_or_die(int refresh_flags)
                die_resolve_conflict("commit");
 }
 
-static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
+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;
@@ -450,7 +450,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
 
        memset(&partial, 0, sizeof(partial));
        partial.strdup_strings = 1;
-       if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec))
+       if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec))
                exit(1);
 
        discard_cache();
@@ -469,7 +469,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
                                                (uintmax_t) getpid()),
                                       LOCK_DIE_ON_ERROR);
 
-       create_base_index();
+       create_base_index(current_head);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
 
@@ -518,12 +518,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        return s->commitable;
 }
 
-static int is_a_merge(const unsigned char *sha1)
+static int is_a_merge(const struct commit *current_head)
 {
-       struct commit *commit = lookup_commit(sha1);
-       if (!commit || parse_commit(commit))
-               die(_("could not parse HEAD commit"));
-       return !!(commit->parents && commit->parents->next);
+       return !!(current_head->parents && current_head->parents->next);
 }
 
 static const char sign_off_header[] = "Signed-off-by: ";
@@ -627,6 +624,7 @@ static char *cut_ident_timestamp_part(char *string)
 }
 
 static int prepare_to_commit(const char *index_file, const char *prefix,
+                            struct commit *current_head,
                             struct wt_status *s,
                             struct strbuf *author_ident)
 {
@@ -848,7 +846,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
         * empty due to conflict resolution, which the user should okay.
         */
        if (!commitable && whence != FROM_MERGE && !allow_empty &&
-           !(amend && is_a_merge(head_sha1))) {
+           !(amend && is_a_merge(current_head))) {
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
                        fputs(_(empty_amend_advice), stderr);
@@ -1006,6 +1004,7 @@ static const char *read_commit_message(const char *name)
 static int parse_and_validate_options(int argc, const char *argv[],
                                      const char * const usage[],
                                      const char *prefix,
+                                     struct commit *current_head,
                                      struct wt_status *s)
 {
        int f = 0;
@@ -1026,11 +1025,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
        if (!use_editor)
                setenv("GIT_EDITOR", ":", 1);
 
-       if (get_sha1("HEAD", head_sha1))
-               initial_commit = 1;
-
        /* Sanity check options */
-       if (amend && initial_commit)
+       if (amend && !current_head)
                die(_("You have nothing to amend."));
        if (amend && whence != FROM_COMMIT)
                die(_("You are in the middle of a %s -- cannot amend."), whence_s());
@@ -1102,12 +1098,12 @@ static int parse_and_validate_options(int argc, const char *argv[],
 }
 
 static int dry_run_commit(int argc, const char **argv, const char *prefix,
-                         struct wt_status *s)
+                         const struct commit *current_head, struct wt_status *s)
 {
        int commitable;
        const char *index_file;
 
-       index_file = prepare_index(argc, argv, prefix, 1);
+       index_file = prepare_index(argc, argv, prefix, current_head, 1);
        commitable = run_status(stdout, index_file, prefix, 0, s);
        rollback_index_files();
 
@@ -1146,7 +1142,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
                return 0;
        }
        if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
-               s->use_color = git_config_colorbool(k, v, -1);
+               s->use_color = git_config_colorbool(k, v);
                return 0;
        }
        if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
@@ -1239,10 +1235,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 
        if (s.relative_paths)
                s.prefix = prefix;
-       if (s.use_color == -1)
-               s.use_color = git_use_color_default;
-       if (diff_use_color_default == -1)
-               diff_use_color_default = git_use_color_default;
 
        switch (status_format) {
        case STATUS_FORMAT_SHORT:
@@ -1260,7 +1252,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
-static void print_summary(const char *prefix, const unsigned char *sha1)
+static void print_summary(const char *prefix, const unsigned char *sha1,
+                         int initial_commit)
 {
        struct rev_info rev;
        struct commit *commit;
@@ -1382,12 +1375,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
        char *nl, *p;
-       unsigned char commit_sha1[20];
+       unsigned char sha1[20];
        struct ref_lock *ref_lock;
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
        int allow_fast_forward = 1;
        struct wt_status s;
+       struct commit *current_head = NULL;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1396,40 +1390,38 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        git_config(git_commit_config, &s);
        determine_whence(&s);
 
-       if (s.use_color == -1)
-               s.use_color = git_use_color_default;
-       argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
-                                         prefix, &s);
-       if (dry_run) {
-               if (diff_use_color_default == -1)
-                       diff_use_color_default = git_use_color_default;
-               return dry_run_commit(argc, argv, prefix, &s);
+       if (get_sha1("HEAD", sha1))
+               current_head = NULL;
+       else {
+               current_head = lookup_commit(sha1);
+               if (!current_head || parse_commit(current_head))
+                       die(_("could not parse HEAD commit"));
        }
-       index_file = prepare_index(argc, argv, prefix, 0);
+       argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
+                                         prefix, current_head, &s);
+       if (dry_run)
+               return dry_run_commit(argc, argv, prefix, current_head, &s);
+       index_file = prepare_index(argc, argv, prefix, current_head, 0);
 
        /* Set up everything for writing the commit object.  This includes
           running hooks, writing the trees, and interacting with the user.  */
-       if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) {
+       if (!prepare_to_commit(index_file, prefix,
+                              current_head, &s, &author_ident)) {
                rollback_index_files();
                return 1;
        }
 
        /* Determine parents */
        reflog_msg = getenv("GIT_REFLOG_ACTION");
-       if (initial_commit) {
+       if (!current_head) {
                if (!reflog_msg)
                        reflog_msg = "commit (initial)";
        } else if (amend) {
                struct commit_list *c;
-               struct commit *commit;
 
                if (!reflog_msg)
                        reflog_msg = "commit (amend)";
-               commit = lookup_commit(head_sha1);
-               if (!commit || parse_commit(commit))
-                       die(_("could not parse HEAD commit"));
-
-               for (c = commit->parents; c; c = c->next)
+               for (c = current_head->parents; c; c = c->next)
                        pptr = &commit_list_insert(c->item, pptr)->next;
        } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
@@ -1437,7 +1429,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
-               pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
+               pptr = &commit_list_insert(current_head, pptr)->next;
                fp = fopen(git_path("MERGE_HEAD"), "r");
                if (fp == NULL)
                        die_errno(_("could not open '%s' for reading"),
@@ -1463,7 +1455,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        reflog_msg = (whence == FROM_CHERRY_PICK)
                                        ? "commit (cherry-pick)"
                                        : "commit";
-               pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
+               pptr = &commit_list_insert(current_head, pptr)->next;
        }
 
        /* Finally, get the commit message */
@@ -1489,7 +1481,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                exit(1);
        }
 
-       if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
+       if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1,
                        author_ident.buf)) {
                rollback_index_files();
                die(_("failed to write commit object"));
@@ -1497,7 +1489,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        strbuf_release(&author_ident);
 
        ref_lock = lock_any_ref_for_update("HEAD",
-                                          initial_commit ? NULL : head_sha1,
+                                          !current_head
+                                          ? NULL
+                                          : current_head->object.sha1,
                                           0);
 
        nl = strchr(sb.buf, '\n');
@@ -1512,7 +1506,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                rollback_index_files();
                die(_("cannot lock HEAD ref"));
        }
-       if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) {
+       if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
                rollback_index_files();
                die(_("cannot update HEAD ref"));
        }
@@ -1534,13 +1528,14 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                struct notes_rewrite_cfg *cfg;
                cfg = init_copy_notes_for_rewrite("amend");
                if (cfg) {
-                       copy_note_for_rewrite(cfg, head_sha1, commit_sha1);
+                       /* we are amending, so current_head is not NULL */
+                       copy_note_for_rewrite(cfg, current_head->object.sha1, sha1);
                        finish_copy_notes_for_rewrite(cfg);
                }
-               run_rewrite_hook(head_sha1, commit_sha1);
+               run_rewrite_hook(current_head->object.sha1, sha1);
        }
        if (!quiet)
-               print_summary(prefix, commit_sha1);
+               print_summary(prefix, sha1, !current_head);
 
        return 0;
 }