Merge branch 'tc/commit-abbrev-fix' into maint
[git/git.git] / builtin / commit.c
similarity index 94%
rename from builtin-commit.c
rename to builtin/commit.c
index 7b7a51a..b71d8f6 100644 (file)
@@ -66,6 +66,7 @@ static char *edit_message, *use_message;
 static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
+static int no_post_rewrite;
 static char *untracked_files_arg, *force_date;
 /*
  * The default commit message cleanup mode will remove the lines
@@ -137,6 +138,7 @@ static struct option builtin_commit_options[] = {
        OPT_BOOLEAN('z', "null", &null_termination,
                    "terminate entries with NUL"),
        OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
+       OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
        { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
        /* end commit contents options */
@@ -305,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         * (B) on failure, rollback the real index.
         */
        if (all || (also && pathspec && *pathspec)) {
-               int fd = hold_locked_index(&index_lock, 1);
+               fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
@@ -320,8 +322,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         *
         * (1) return the name of the real index file.
         *
-        * The caller should run hooks on the real index, and run
-        * hooks on the real index, and create commit from the_index.
+        * The caller should run hooks on the real index,
+        * and create commit from the_index.
         * We still need to refresh the index here.
         */
        if (!pathspec || !*pathspec) {
@@ -453,15 +455,21 @@ static void determine_author_info(void)
                if (!a)
                        die("invalid commit: %s", use_message);
 
-               lb = strstr(a + 8, " <");
-               rb = strstr(a + 8, "> ");
-               eol = strchr(a + 8, '\n');
-               if (!lb || !rb || !eol)
+               lb = strchrnul(a + strlen("\nauthor "), '<');
+               rb = strchrnul(lb, '>');
+               eol = strchrnul(rb, '\n');
+               if (!*lb || !*rb || !*eol)
                        die("invalid commit: %s", use_message);
 
-               name = xstrndup(a + 8, lb - (a + 8));
-               email = xstrndup(lb + 2, rb - (lb + 2));
-               date = xstrndup(rb + 2, eol - (rb + 2));
+               if (lb == a + strlen("\nauthor "))
+                       /* \nauthor <foo@example.com> */
+                       name = xcalloc(1, 1);
+               else
+                       name = xmemdupz(a + strlen("\nauthor "),
+                                       (lb - strlen(" ") -
+                                        (a + strlen("\nauthor "))));
+               email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
+               date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> ")));
        }
 
        if (force_author) {
@@ -1015,6 +1023,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
 int cmd_status(int argc, const char **argv, const char *prefix)
 {
        struct wt_status s;
+       int fd;
        unsigned char sha1[20];
        static struct option builtin_status_options[] = {
                OPT__VERBOSE(&verbose),
@@ -1048,6 +1057,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 
        read_cache_preload(s.pathspec);
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+
+       fd = hold_locked_index(&index_lock, 0);
+       if (0 <= fd) {
+               if (!write_cache(fd, active_cache, active_nr))
+                       commit_locked_index(&index_lock);
+               rollback_lock_file(&index_lock);
+       }
+
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
        s.in_merge = in_merge;
        wt_status_collect(&s);
@@ -1158,6 +1175,40 @@ static int git_commit_config(const char *k, const char *v, void *cb)
        return git_status_config(k, v, s);
 }
 
+static const char post_rewrite_hook[] = "hooks/post-rewrite";
+
+static int run_rewrite_hook(const unsigned char *oldsha1,
+                           const unsigned char *newsha1)
+{
+       /* oldsha1 SP newsha1 LF NUL */
+       static char buf[2*40 + 3];
+       struct child_process proc;
+       const char *argv[3];
+       int code;
+       size_t n;
+
+       if (access(git_path(post_rewrite_hook), X_OK) < 0)
+               return 0;
+
+       argv[0] = git_path(post_rewrite_hook);
+       argv[1] = "amend";
+       argv[2] = NULL;
+
+       memset(&proc, 0, sizeof(proc));
+       proc.argv = argv;
+       proc.in = -1;
+       proc.stdout_to_stderr = 1;
+
+       code = start_command(&proc);
+       if (code)
+               return code;
+       n = snprintf(buf, sizeof(buf), "%s %s\n",
+                    sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
+       write_in_full(proc.in, buf, n);
+       close(proc.in);
+       return finish_command(&proc);
+}
+
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
        struct strbuf sb = STRBUF_INIT;
@@ -1301,6 +1352,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        rerere(0);
        run_hook(get_index_file(), "post-commit", NULL);
+       if (amend && !no_post_rewrite) {
+               struct notes_rewrite_cfg *cfg;
+               cfg = init_copy_notes_for_rewrite("amend");
+               if (cfg) {
+                       copy_note_for_rewrite(cfg, head_sha1, commit_sha1);
+                       finish_copy_notes_for_rewrite(cfg);
+               }
+               run_rewrite_hook(head_sha1, commit_sha1);
+       }
        if (!quiet)
                print_summary(prefix, commit_sha1);