commit 75a8c854e063f97e5a2605f5256a1ce15ffb2f24 from: Stefan Sperling via: Thomas Adam date: Fri Feb 17 16:23:18 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 - 96d694ac3bc159099a9ad93aa49ec7ac1764b18d commit + 75a8c854e063f97e5a2605f5256a1ce15ffb2f24 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 - 6e5b65aa69900bbf246ac029c6cd4c455abe1b84 blob + bee0d18c081539ca419adef37c4d86b0cb38d282 --- 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);