"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Mark Jamsek <mark@jamsek.com>
Subject:
got backout/cherrypick auto commit
To:
Game of Trees <gameoftrees@openbsd.org>
Date:
Thu, 19 Jan 2023 19:05:44 +1100

Download raw body.

Thread
As per the subject and todo item, the below diff introduces the -a flag
to both the backout and cherrypick commands.

I was glad to see this on the todo list because I'll use 'got cy -a'
a lot! I often run log or tog to copypasta the log message before
running `got cy branch && got ci -m msg` so I was keen to see this
implemented.

I'm really looking for feedback though as I'm not sure if the annotated
log message and base-commit bump stsp mentioned is adequate. Thanks!

diffstat eca2b1d0d697cef723df2d1394b84b636c02ced0 refs/heads/main
 M  got/got.1               |   26+  0-
 M  got/got.c               |  115+  6-
 M  include/got_worktree.h  |    4+  0-
 M  lib/worktree.c          |   23+  0-

4 files changed, 168 insertions(+), 6 deletions(-)

diff eca2b1d0d697cef723df2d1394b84b636c02ced0 refs/heads/main
commit - eca2b1d0d697cef723df2d1394b84b636c02ced0
commit + e3bc7ce6dca5ed5a66f727442aea02dd81edc176
blob - 06f7a35a329a5563b7c304c6b2be8b38e249e518
blob + 98b9b0dc8c54279f115f4b2bbb2525d61a74b44c
--- got/got.1
+++ got/got.1
@@ -2012,6 +2012,18 @@ conflicts must be resolved first.
 .Cm got update .
 If any relevant files already contain merge conflicts, these
 conflicts must be resolved first.
+.Pp
+The options for
+.Nm
+.Cm cherrypick
+are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Automatically create a new commit on the work tree's current branch using the
+author, log message, and merged changes of
+.Ar commit .
+.El
+.Pp
 .Tg bo
 .It Cm backout Ar commit
 .Dl Pq alias: Cm bo
@@ -2055,6 +2067,20 @@ conflicts must be resolved first.
 .Cm got update .
 If any relevant files already contain merge conflicts, these
 conflicts must be resolved first.
+.Pp
+The options for
+.Nm
+.Cm backout
+are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Automatically create a new commit on the work tree's current branch using
+.Ar commit Ns 's
+reverse-merged changes and log message prepended with
+.Qq backout:\ \&
+and its abbreviated object ID.
+.El
+.Pp
 .Tg rb
 .It Xo
 .Cm rebase
blob - f1564fe9067f8708e5f87d50539aa46985cdc197
blob + 20e819a2087f53305c3316ae9f5dd53defbdc028
--- got/got.c
+++ got/got.c
@@ -9454,11 +9454,105 @@ usage_cherrypick(void)
 __dead static void
 usage_cherrypick(void)
 {
-	fprintf(stderr, "usage: %s cherrypick commit-id\n", getprogname());
+	fprintf(stderr, "usage: %s cherrypick [-a] commit-id\n", getprogname());
 	exit(1);
 }
 
 static const struct got_error *
+autocommit_merged_changes(struct got_commit_object *commit,
+    struct got_update_progress_arg *upa, const char *backout_commit_id,
+    struct got_worktree *worktree, struct got_repository *repo)
+{
+	const struct got_error			*err = NULL;
+	struct collect_commit_logmsg_arg	 cla;
+	struct got_pathlist_head		 paths;
+	const char				*author = NULL;
+	struct got_object_id			*commit_id = NULL;
+	char					*bo = NULL, *committer = NULL;
+	char					*logmsg0, *logmsg = NULL;
+	char					*idstr = NULL;
+
+	/*
+	 * XXX Don't think we should error here as 'got {backout,cherrypick}'
+	 * without -a doesn't error on these upa status codes.
+	 */
+	if (upa->conflicts || upa->missing || upa->not_deleted ||
+	    upa->obstructed || upa->unversioned ||
+	    upa->not_updated /* XXX shouldn't happen in cherrypick/backout? */)
+		return NULL;
+
+	TAILQ_INIT(&paths);
+	memset(&cla, 0, sizeof(cla));
+
+	err = got_pathlist_append(&paths, "", NULL);
+	if (err)
+		return err;
+
+	err = got_object_commit_get_logmsg(&logmsg, commit);
+	if (err)
+		goto done;
+
+	if (backout_commit_id) {
+		if (asprintf(&bo, "backout %.10s: ", backout_commit_id) == -1) {
+			err = got_error_from_errno("asprintf");
+			goto done;
+		}
+	}
+
+	if (bo) {
+		if (asprintf(&logmsg0, "\n%s%s", bo, logmsg + 1) == -1) {
+			err = got_error_from_errno("asprintf");
+			goto done;
+		}
+		free(logmsg);
+		logmsg = logmsg0;
+	}
+
+	err = get_author(&committer, repo, worktree);
+	if (err)
+		goto done;
+
+	/* don't use author in auto backout commit, committer is the author */
+	if (bo == NULL)
+		author = got_object_commit_get_author(commit);
+	if (author == NULL)
+		author = committer;
+
+	cla.branch_name = got_worktree_get_head_ref_name(worktree);
+	if (strncmp(cla.branch_name, "refs/heads/", 11) != 0) {
+		err = got_error(GOT_ERR_COMMIT_BRANCH);
+		goto done;
+	}
+	cla.branch_name += 11;
+	cla.non_interactive = 1;
+	cla.cmdline_log = logmsg;
+	cla.repo_path = got_repo_get_path(repo);
+	cla.worktree_path = got_worktree_get_root_path(worktree);
+
+	err = got_worktree_commit(&commit_id, worktree, &paths,
+	    author, committer, 0, 0, collect_commit_logmsg, &cla,
+	    print_status, NULL, repo);
+	if (err)
+		goto done;
+
+	err = got_object_id_str(&idstr, commit_id);
+	if (err)
+		goto done;
+
+	printf("Created commit %s\n", idstr);
+	err = got_worktree_autocommit_complete(worktree, repo);
+
+done:
+	free(bo);
+	free(idstr);
+	free(logmsg);
+	free(commit_id);
+	free(committer);
+	got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
+	return err;
+}
+
+static const struct got_error *
 cmd_cherrypick(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
@@ -9468,12 +9562,15 @@ cmd_cherrypick(int argc, char *argv[])
 	struct got_object_id *commit_id = NULL;
 	struct got_commit_object *commit = NULL;
 	struct got_object_qid *pid;
-	int ch;
+	int ch, auto_commit = 0;;
 	struct got_update_progress_arg upa;
 	int *pack_fds = NULL;
 
-	while ((ch = getopt(argc, argv, "")) != -1) {
+	while ((ch = getopt(argc, argv, "a")) != -1) {
 		switch (ch) {
+		case 'a':
+			auto_commit = 1;
+			break;
 		default:
 			usage_cherrypick();
 			/* NOTREACHED */
@@ -9541,6 +9638,10 @@ done:
 	if (upa.did_something)
 		printf("Merged commit %s\n", commit_id_str);
 	print_merge_progress_stats(&upa);
+
+	if (auto_commit && upa.did_something)
+		error = autocommit_merged_changes(commit, &upa, NULL,
+		    worktree, repo);
 done:
 	if (commit)
 		got_object_commit_close(commit);
@@ -9565,7 +9666,7 @@ usage_backout(void)
 __dead static void
 usage_backout(void)
 {
-	fprintf(stderr, "usage: %s backout commit-id\n", getprogname());
+	fprintf(stderr, "usage: %s backout [-a] commit-id\n", getprogname());
 	exit(1);
 }
 
@@ -9579,12 +9680,16 @@ cmd_backout(int argc, char *argv[])
 	struct got_object_id *commit_id = NULL;
 	struct got_commit_object *commit = NULL;
 	struct got_object_qid *pid;
-	int ch;
+	int ch, auto_commit = 0;;
 	struct got_update_progress_arg upa;
+
 	int *pack_fds = NULL;
 
-	while ((ch = getopt(argc, argv, "")) != -1) {
+	while ((ch = getopt(argc, argv, "a")) != -1) {
 		switch (ch) {
+		case 'a':
+			auto_commit = 1;
+			break;
 		default:
 			usage_backout();
 			/* NOTREACHED */
@@ -9655,6 +9760,10 @@ done:
 	if (upa.did_something)
 		printf("Backed out commit %s\n", commit_id_str);
 	print_merge_progress_stats(&upa);
+
+	if (auto_commit && upa.did_something)
+		error = autocommit_merged_changes(commit, &upa, commit_id_str,
+		    worktree, repo);
 done:
 	if (commit)
 		got_object_commit_close(commit);
blob - d3c26b9a044948f5b93e8f2f6adf673b8dd7e599
blob + a1682caee9c4d198472296991b3a16ed4a8bc568
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -571,3 +571,7 @@ got_worktree_patch_complete(struct got_fileindex *, co
 /* Complete the patch operation. */
 const struct got_error *
 got_worktree_patch_complete(struct got_fileindex *, const char *);
+
+
+const struct got_error *
+got_worktree_autocommit_complete(struct got_worktree *, struct got_repository *);
blob - febf807fc9a1e5b9c2cdab208adc8217a492980e
blob + 56b6756df955ba8abe906fc8084dc56ce4343343
--- lib/worktree.c
+++ lib/worktree.c
@@ -9355,3 +9355,26 @@ got_worktree_patch_complete(struct got_fileindex *file
 
 	return err;
 }
+
+const struct got_error *
+got_worktree_autocommit_complete(struct got_worktree *worktree,
+    struct got_repository *repo)
+{
+	const struct got_error	*err, *sync_err;
+	struct got_fileindex	*fileindex = NULL;
+	char			*fileindex_path = NULL;
+
+	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	if (err)
+		return err;
+
+	err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
+	sync_err = sync_fileindex(fileindex, fileindex_path);
+	if (sync_err && err == NULL)
+		err = sync_err;
+
+	got_fileindex_free(fileindex);
+	free(fileindex_path);
+	return err;
+}
+

-- 
Mark Jamsek <fnc.bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80  E6E2 2930 DC66 86EE CF68