commit 91a3781a11d1b2c483221d9dca87d72aea17637b from: Stefan Sperling date: Thu Feb 09 14:33:28 2023 UTC make edits made to comments count as a log message modification This supports use of cherrypick/backout without requiring the user to modify the log message of the original commit. ok jamsek, op commit - 575dc3f9456affacd711c081f85e2b41f2544206 commit + 91a3781a11d1b2c483221d9dca87d72aea17637b blob - 518e73d32dd54163f0c184e0373f963ae473079b blob + 6909ba95d7617d65c7fcad655d3baa1f1543340a --- got/got.1 +++ got/got.1 @@ -2038,8 +2038,13 @@ When a file changed by is committed with .Cm got commit , the log messages of relevant merged commits will then appear in the editor, -where the messages must be further adjusted to convey the reasons for +where the messages should be further adjusted to convey the reasons for cherrypicking the changes. +At the very least, comment lines must be removed. +Otherwise +.Cm got commit +will fail with an unmodified log message error. +.Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , @@ -2141,8 +2146,13 @@ When a file changed by is committed with .Cm got commit , the log messages of relevant reverse-merged commits will then appear in -the editor, where the messages must be further adjusted to convey the +the editor, where the messages should be further adjusted to convey the reasons for backing out the changes. +At the very least, comment lines must be removed. +Otherwise +.Cm got commit +will fail with an unmodified log message error. +.Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , blob - e7d51531acf964d92ac89f71868de68018e76ac8 blob + e4bb98750bf47f68c270846e694ff0d461408b05 --- got/got.c +++ got/got.c @@ -389,13 +389,60 @@ doneediting: } static const struct got_error * +read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize, + int strip_comments) +{ + const struct got_error *err = NULL; + char *line = NULL; + size_t linesize = 0; + + *logmsg = NULL; + *len = 0; + + if (fseeko(fp, 0L, SEEK_SET) == -1) + return got_error_from_errno("fseeko"); + + *logmsg = malloc(filesize + 1); + if (*logmsg == NULL) + return got_error_from_errno("malloc"); + (*logmsg)[0] = '\0'; + + while (getline(&line, &linesize, fp) != -1) { + if ((strip_comments && line[0] == '#') || + (*len == 0 && line[0] == '\n')) + continue; /* remove comments and leading empty lines */ + *len = strlcat(*logmsg, line, filesize + 1); + if (*len >= filesize + 1) { + err = got_error(GOT_ERR_NO_SPACE); + goto done; + } + } + if (ferror(fp)) { + err = got_ferror(fp, GOT_ERR_IO); + goto done; + } + + while (*len > 0 && (*logmsg)[*len - 1] == '\n') { + (*logmsg)[*len - 1] = '\0'; + (*len)--; + } +done: + free(line); + if (err) { + free(*logmsg); + *logmsg = NULL; + *len = 0; + } + return err; +} + +static const struct got_error * edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path, const char *initial_content, size_t initial_content_len, int require_modification) { const struct got_error *err = NULL; char *line = NULL; - size_t linesize = 0; struct stat st, st2; FILE *fp = NULL; size_t len, logmsg_len; @@ -435,8 +482,8 @@ edit_logmsg(char **logmsg, const char *editor, const c s = buf; len = 0; while ((line = strsep(&s, "\n")) != NULL) { - if ((line[0] == '#' || (len == 0 && line[0] == '\n'))) - continue; /* remove comments and leading empty lines */ + if (len == 0 && line[0] == '\n') + continue; /* remove leading empty lines */ len = strlcat(initial_content_stripped, line, initial_content_len + 1); if (len >= initial_content_len + 1) { @@ -449,47 +496,35 @@ edit_logmsg(char **logmsg, const char *editor, const c len--; } - logmsg_len = st2.st_size; - *logmsg = malloc(logmsg_len + 1); - if (*logmsg == NULL) - return got_error_from_errno("malloc"); - (*logmsg)[0] = '\0'; - fp = fopen(logmsg_path, "re"); if (fp == NULL) { err = got_error_from_errno("fopen"); goto done; } - len = 0; - while (getline(&line, &linesize, fp) != -1) { - if ((line[0] == '#' || (len == 0 && line[0] == '\n'))) - continue; /* remove comments and leading empty lines */ - len = strlcat(*logmsg, line, logmsg_len + 1); - if (len >= logmsg_len + 1) { - err = got_error(GOT_ERR_NO_SPACE); - goto done; - } - } - free(line); - if (ferror(fp)) { - err = got_ferror(fp, GOT_ERR_IO); + /* + * Check whether the log message was modified. + * Editing or removal of comments does count as a modifcation to + * support reuse of existing log messages during cherrypick/backout. + */ + err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size, 0); + if (err) goto done; - } - while (len > 0 && (*logmsg)[len - 1] == '\n') { - (*logmsg)[len - 1] = '\0'; - len--; - } + if (require_modification && + strcmp(*logmsg, initial_content_stripped) == 0) + err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, + "no changes made to commit message, aborting"); - if (len == 0) { + /* Read log message again, stripping comments this time around. */ + free(*logmsg); + err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size, 1); + if (err) + goto done; + if (logmsg_len == 0) { err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty, aborting"); goto done; } - if (require_modification && - strcmp(*logmsg, initial_content_stripped) == 0) - err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, - "no changes made to commit message, aborting"); done: free(initial_content_stripped); free(buf);