Merge branch 'hs/simplify-bit-setting-in-fsck-tree'
[gitweb.git] / builtin / commit.c
index fedb45af8c65d28c3b43b3b74362e589d81a95ee..d9550c54d02bbd1ba4df87734433dea4a7097e2e 100644 (file)
@@ -113,6 +113,7 @@ static char *sign_commit;
 static enum {
        CLEANUP_SPACE,
        CLEANUP_NONE,
+       CLEANUP_SCISSORS,
        CLEANUP_ALL
 } cleanup_mode;
 static const char *cleanup_arg;
@@ -234,7 +235,7 @@ static int list_paths(struct string_list *list, const char *with_tree,
 
                if (ce->ce_flags & CE_UPDATE)
                        continue;
-               if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
+               if (!ce_path_match(ce, pattern, m))
                        continue;
                item = string_list_insert(list, ce->name);
                if (ce_skip_worktree(ce))
@@ -307,7 +308,6 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
        int fd;
        struct string_list partial;
        struct pathspec pathspec;
-       char *old_index_env = NULL;
        int refresh_flags = REFRESH_QUIET;
 
        if (is_status)
@@ -320,6 +320,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
                die(_("index file corrupt"));
 
        if (interactive) {
+               char *old_index_env = NULL;
                fd = hold_locked_index(&index_lock, 1);
 
                refresh_cache_or_die(refresh_flags);
@@ -600,19 +601,17 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 {
        struct stat statbuf;
        struct strbuf committer_ident = STRBUF_INIT;
-       int commitable, saved_color_setting;
+       int commitable;
        struct strbuf sb = STRBUF_INIT;
-       char *buffer;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
-       int ident_shown = 0;
        int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
        int old_display_comment_prefix;
 
        /* This checks and barfs if author is badly specified */
        determine_author_info(author_ident);
 
-       if (!no_verify && run_hook(index_file, "pre-commit", NULL))
+       if (!no_verify && run_commit_hook(use_editor, index_file, "pre-commit", NULL))
                return 0;
 
        if (squash_message) {
@@ -649,6 +648,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                  logfile);
                hook_arg1 = "message";
        } 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"));
@@ -733,7 +733,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                eol = nl - sb.buf;
                        else
                                eol = sb.len;
-                       if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) {
+                       if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
                                ignore_footer = sb.len - previous;
                                break;
                        }
@@ -753,8 +753,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        /* This checks if committer ident is explicitly given */
        strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
        if (use_editor && include_status) {
+               int ident_shown = 0;
+               int saved_color_setting;
                char *ai_tmp, *ci_tmp;
-               if (whence != FROM_COMMIT)
+               if (whence != FROM_COMMIT) {
+                       if (cleanup_mode == CLEANUP_SCISSORS)
+                               wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                            whence == FROM_MERGE
                                ? _("\n"
@@ -770,6 +774,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                git_path(whence == FROM_MERGE
                                         ? "MERGE_HEAD"
                                         : "CHERRY_PICK_HEAD"));
+               }
 
                fprintf(s->fp, "\n");
                if (cleanup_mode == CLEANUP_ALL)
@@ -777,6 +782,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\nwith '%c' will be ignored, and an empty"
                                  " message aborts the commit.\n"), comment_line_char);
+               else if (cleanup_mode == CLEANUP_SCISSORS && whence == FROM_COMMIT)
+                       wt_status_add_cut_line(s->fp);
                else /* CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
@@ -866,8 +873,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                return 0;
        }
 
-       if (run_hook(index_file, "prepare-commit-msg",
-                    git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
+       if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
+                           git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
                return 0;
 
        if (use_editor) {
@@ -883,7 +890,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        }
 
        if (!no_verify &&
-           run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
+           run_commit_hook(use_editor, index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
                return 0;
        }
 
@@ -904,7 +911,7 @@ static int rest_is_empty(struct strbuf *sb, int start)
                        eol = sb->len;
 
                if (strlen(sign_off_header) <= eol - i &&
-                   !prefixcmp(sb->buf + i, sign_off_header)) {
+                   starts_with(sb->buf + i, sign_off_header)) {
                        i = eol;
                        continue;
                }
@@ -1067,8 +1074,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
                use_editor = 0;
        if (0 <= edit_flag)
                use_editor = edit_flag;
-       if (!use_editor)
-               setenv("GIT_EDITOR", ":", 1);
 
        /* Sanity check options */
        if (amend && !current_head)
@@ -1132,6 +1137,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
                cleanup_mode = CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "strip"))
                cleanup_mode = CLEANUP_ALL;
+       else if (!strcmp(cleanup_arg, "scissors"))
+               cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
 
@@ -1183,7 +1190,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
 {
        struct wt_status *s = cb;
 
-       if (!prefixcmp(k, "column."))
+       if (starts_with(k, "column."))
                return git_column_config(k, v, "status", &s->colopts);
        if (!strcmp(k, "status.submodulesummary")) {
                int is_bool;
@@ -1211,7 +1218,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
                s->display_comment_prefix = git_config_bool(k, v);
                return 0;
        }
-       if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
+       if (starts_with(k, "status.color.") || starts_with(k, "color.status.")) {
                int slot = parse_status_slot(k, 13);
                if (slot < 0)
                        return 0;
@@ -1338,7 +1345,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
        commit = lookup_commit(sha1);
        if (!commit)
                die(_("couldn't look up newly created commit"));
-       if (!commit || parse_commit(commit))
+       if (parse_commit(commit))
                die(_("could not parse newly created commit"));
 
        strbuf_addstr(&format, "format:%h] %s");
@@ -1377,7 +1384,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 
        head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
        printf("[%s%s ",
-               !prefixcmp(head, "refs/heads/") ?
+               starts_with(head, "refs/heads/") ?
                        head + 11 :
                        !strcmp(head, "HEAD") ?
                                _("detached HEAD") :
@@ -1406,6 +1413,10 @@ static int git_commit_config(const char *k, const char *v, void *cb)
        }
        if (!strcmp(k, "commit.cleanup"))
                return git_config_string(&cleanup_arg, k, v);
+       if (!strcmp(k, "commit.gpgsign")) {
+               sign_commit = git_config_bool(k, v) ? "" : NULL;
+               return 0;
+       }
 
        status = git_gpg_config(k, v, NULL);
        if (status)
@@ -1445,6 +1456,29 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
        return finish_command(&proc);
 }
 
+int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
+{
+       const char *hook_env[3] =  { NULL };
+       char index[PATH_MAX];
+       va_list args;
+       int ret;
+
+       snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+       hook_env[0] = index;
+
+       /*
+        * Let the hook know that no editor will be launched.
+        */
+       if (!editor_is_used)
+               hook_env[1] = "GIT_EDITOR=:";
+
+       va_start(args, name);
+       ret = run_hook_ve(hook_env, name, args);
+       va_end(args);
+
+       return ret;
+}
+
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
        static struct wt_status s;
@@ -1510,7 +1544,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        struct ref_lock *ref_lock;
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
-       int allow_fast_forward = 1;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
 
@@ -1525,7 +1558,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                current_head = NULL;
        else {
                current_head = lookup_commit_or_die(sha1, "HEAD");
-               if (!current_head || parse_commit(current_head))
+               if (parse_commit(current_head))
                        die(_("could not parse HEAD commit"));
        }
        argc = parse_and_validate_options(argc, argv, builtin_commit_options,
@@ -1558,6 +1591,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
                FILE *fp;
+               int allow_fast_forward = 1;
 
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
@@ -1600,8 +1634,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                die(_("could not read commit message: %s"), strerror(saved_errno));
        }
 
-       /* Truncate the message just before the diff, if any. */
-       if (verbose)
+       if (verbose || /* Truncate the message just before the diff, if any. */
+           cleanup_mode == CLEANUP_SCISSORS)
                wt_status_truncate_message_at_cut_line(&sb);
 
        if (cleanup_mode != CLEANUP_NONE)
@@ -1669,7 +1703,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                     "not exceeded, and then \"git reset HEAD\" to recover."));
 
        rerere(0);
-       run_hook(get_index_file(), "post-commit", NULL);
+       run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
                struct notes_rewrite_cfg *cfg;
                cfg = init_copy_notes_for_rewrite("amend");