commit e0870e443a8dfb50091e64747658a3e0740f82bb from: Stefan Sperling date: Mon May 13 16:37:36 2019 UTC store commit message in work tree and leave it there in case of error commit - e2ba3d0783eb02d645fa15d937c911565bec60f7 commit + e0870e443a8dfb50091e64747658a3e0740f82bb blob - 8e2c73d13cbf00f3514b6e1cabe430148a348f14 blob + 8c9793810718d7086090d59a084fe0d09f7c2d28 --- got/got.c +++ got/got.c @@ -2199,21 +2199,25 @@ doneediting: struct collect_commit_logmsg_arg { const char *cmdline_log; const char *editor; + const char *worktree_path; + char *logmsg_path; }; + static const struct got_error * collect_commit_logmsg(struct got_pathlist_head *commitable_paths, char **logmsg, void *arg) { + const char *initial_content = "\n# changes to be committed:\n"; struct got_pathlist_entry *pe; const struct got_error *err = NULL; - char *tmpfile = NULL; + char *template = NULL; struct collect_commit_logmsg_arg *a = arg; char buf[1024]; struct stat st, st2; FILE *fp; size_t len; - int fd; + int fd, content_changed = 0; /* if a message was specified on the command line, just use it */ if (a->cmdline_log != NULL && strlen(a->cmdline_log) != 0) { @@ -2225,12 +2229,14 @@ collect_commit_logmsg(struct got_pathlist_head *commit return NULL; } - err = got_opentemp_named_fd(&tmpfile, &fd, "/tmp/got-XXXXXXXXXX"); + if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1) + return got_error_prefix_errno("asprintf"); + + err = got_opentemp_named_fd(&a->logmsg_path, &fd, template); if (err) - return err; + goto done; - dprintf(fd, "\n" - "# changes to be committed:\n"); + dprintf(fd, initial_content); TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; @@ -2238,22 +2244,25 @@ collect_commit_logmsg(struct got_pathlist_head *commit } close(fd); - if (stat(tmpfile, &st) == -1) { - err = got_error_prefix_errno2("stat", tmpfile); + if (stat(a->logmsg_path, &st) == -1) { + err = got_error_prefix_errno2("stat", a->logmsg_path); goto done; } - if (spawn_editor(a->editor, tmpfile) == -1) { + if (spawn_editor(a->editor, a->logmsg_path) == -1) { err = got_error_prefix_errno("failed spawning editor"); goto done; } - if (stat(tmpfile, &st2) == -1) { + if (stat(a->logmsg_path, &st2) == -1) { err = got_error_prefix_errno("stat"); goto done; } if (st.st_mtime == st2.st_mtime && st.st_size == st2.st_size) { + unlink(a->logmsg_path); + free(a->logmsg_path); + a->logmsg_path = NULL; err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "no changes made to commit message, aborting"); goto done; @@ -2267,8 +2276,10 @@ collect_commit_logmsg(struct got_pathlist_head *commit } len = 0; - fp = fopen(tmpfile, "r"); + fp = fopen(a->logmsg_path, "r"); while (fgets(buf, sizeof(buf), fp) != NULL) { + if (!content_changed && strcmp(buf, initial_content) != 0) + content_changed = 1; if (buf[0] == '#' || (len == 0 && buf[0] == '\n')) continue; len = strlcat(*logmsg, buf, st2.st_size); @@ -2280,17 +2291,16 @@ collect_commit_logmsg(struct got_pathlist_head *commit len--; } - if (len == 0) { + if (len == 0 || !content_changed) { + unlink(a->logmsg_path); + free(a->logmsg_path); + a->logmsg_path = NULL; err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty, aborting"); goto done; } done: - if (tmpfile) { - unlink(tmpfile); - free(tmpfile); - } - + free(template); return err; } @@ -2361,11 +2371,20 @@ cmd_commit(int argc, char *argv[]) goto done; cl_arg.editor = editor; cl_arg.cmdline_log = logmsg; + cl_arg.worktree_path = got_worktree_get_root_path(worktree); + cl_arg.logmsg_path = NULL; error = got_worktree_commit(&id, worktree, path, got_author, NULL, collect_commit_logmsg, &cl_arg, print_status, NULL, repo); - if (error) + if (error) { + if (cl_arg.logmsg_path) + fprintf(stderr, "%s: log message preserved in %s\n", + getprogname(), cl_arg.logmsg_path); goto done; + } + if (cl_arg.logmsg_path) + unlink(cl_arg.logmsg_path); + error = got_object_id_str(&id_str, id); if (error) goto done;