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

From:
Mark Jamsek <mark@jamsek.com>
Subject:
got histedit -d (drop all commits)
To:
Game of Trees <gameoftrees@openbsd.org>
Date:
Tue, 31 Jan 2023 00:16:26 +1100

Download raw body.

Thread
As discussed on irc, the below diff introduces the histedit -d flag,
which is like -f but drops all commits. Regress has also been added for
the new flag.

While writing this, I noticed we missed a conflict check for -f and -e,
which is included in the diff, but I should probably send as a separate
commit.

diffstat /home/mark/src/got
 M  got/got.1                    |    9+   1-
 M  got/got.c                    |   41+  11-
 M  regress/cmdline/histedit.sh  |  117+   0-

3 files changed, 167 insertions(+), 12 deletions(-)

diff /home/mark/src/got
commit - d6669aa7295427afff77c3466009e1d56a223644
path + /home/mark/src/got
blob - 9ca39428e1178142919dfd78df6b0381cda7f8b6
file + got/got.1
--- got/got.1
+++ got/got.1
@@ -2391,7 +2391,7 @@ None of the other options can be used together with
 .Tg he
 .It Xo
 .Cm histedit
-.Op Fl aceflmX
+.Op Fl acdeflmX
 .Op Fl F Ar histedit-script
 .Op Ar branch
 .Xc
@@ -2569,6 +2569,14 @@ If this option is used, no other command-line argument
 .It Fl c
 Continue an interrupted histedit operation.
 If this option is used, no other command-line arguments are allowed.
+.It Fl d
+Drop all commits.
+This option is a quick equivalent to a histedit script which drops all
+commits.
+The
+.Fl d
+option can only be used when starting a new histedit operation.
+If this option is used, no other command-line arguments are allowed.
 .It Fl e
 Interrupt the histedit operation for editing after merging each commit.
 This option is a quick equivalent to a histedit script which uses the
blob - 9483d742cf03e1b1222540c193592d1caed4458a
file + got/got.c
--- got/got.c
+++ got/got.c
@@ -11357,7 +11357,7 @@ usage_histedit(void)
 __dead static void
 usage_histedit(void)
 {
-	fprintf(stderr, "usage: %s histedit [-aceflmX] [-F histedit-script] "
+	fprintf(stderr, "usage: %s histedit [-acdeflmX] [-F histedit-script] "
 	    "[branch]\n", getprogname());
 	exit(1);
 }
@@ -11424,8 +11424,8 @@ histedit_write_commit_list(struct got_object_id_queue 
 
 static const struct got_error *
 histedit_write_commit_list(struct got_object_id_queue *commits,
-    FILE *f, int edit_logmsg_only, int fold_only, int edit_only,
-    struct got_repository *repo)
+    FILE *f, int edit_logmsg_only, int fold_only, int drop_only,
+    int edit_only, struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
 	struct got_object_qid *qid;
@@ -11436,7 +11436,9 @@ histedit_write_commit_list(struct got_object_id_queue 
 
 	STAILQ_FOREACH(qid, commits, entry) {
 		histedit_cmd = got_histedit_cmds[0].name;
-		if (edit_only)
+		if (drop_only)
+			histedit_cmd = "drop";
+		else if (edit_only)
 			histedit_cmd = "edit";
 		else if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
 			histedit_cmd = "fold";
@@ -11855,7 +11857,7 @@ histedit_edit_script(struct got_histedit_list *histedi
 static const struct got_error *
 histedit_edit_script(struct got_histedit_list *histedit_cmds,
     struct got_object_id_queue *commits, const char *branch_name,
-    int edit_logmsg_only, int fold_only, int edit_only,
+    int edit_logmsg_only, int fold_only, int drop_only, int edit_only,
     struct got_repository *repo)
 {
 	const struct got_error *err;
@@ -11871,11 +11873,11 @@ histedit_edit_script(struct got_histedit_list *histedi
 		goto done;
 
 	err = histedit_write_commit_list(commits, f, edit_logmsg_only,
-	    fold_only, edit_only, repo);
+	    fold_only, drop_only, edit_only, repo);
 	if (err)
 		goto done;
 
-	if (edit_logmsg_only || fold_only || edit_only) {
+	if (drop_only || edit_logmsg_only || fold_only || edit_only) {
 		rewind(f);
 		err = histedit_parse_list(histedit_cmds, f, repo);
 	} else {
@@ -12006,7 +12008,7 @@ histedit_edit_list_retry(struct got_histedit_list *his
 		} else if (resp == 'r') {
 			histedit_free_list(histedit_cmds);
 			err = histedit_edit_script(histedit_cmds,
-			    commits, branch_name, 0, 0, 0, repo);
+			    commits, branch_name, 0, 0, 0, 0, repo);
 			if (err) {
 				if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
 				    err->code != GOT_ERR_HISTEDIT_CMD)
@@ -12198,7 +12200,7 @@ cmd_histedit(int argc, char *argv[])
 	int ch, rebase_in_progress = 0, merge_in_progress = 0;
 	struct got_update_progress_arg upa;
 	int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
-	int edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
+	int drop_only = 0, edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
 	int list_backups = 0, delete_backups = 0;
 	const char *edit_script_path = NULL;
 	struct got_object_id_queue commits;
@@ -12214,7 +12216,7 @@ cmd_histedit(int argc, char *argv[])
 	TAILQ_INIT(&merged_paths);
 	memset(&upa, 0, sizeof(upa));
 
-	while ((ch = getopt(argc, argv, "aceF:flmX")) != -1) {
+	while ((ch = getopt(argc, argv, "acdeF:flmX")) != -1) {
 		switch (ch) {
 		case 'a':
 			abort_edit = 1;
@@ -12222,6 +12224,9 @@ cmd_histedit(int argc, char *argv[])
 		case 'c':
 			continue_edit = 1;
 			break;
+		case 'd':
+			drop_only = 1;
+			break;
 		case 'e':
 			edit_only = 1;
 			break;
@@ -12278,6 +12283,20 @@ cmd_histedit(int argc, char *argv[])
 		option_conflict('e', 'm');
 	if (edit_script_path && edit_only)
 		option_conflict('F', 'e');
+	if (fold_only && edit_only)
+		option_conflict('f', 'e');
+	if (drop_only && abort_edit)
+		option_conflict('d', 'a');
+	if (drop_only && continue_edit)
+		option_conflict('d', 'c');
+	if (drop_only && edit_logmsg_only)
+		option_conflict('d', 'm');
+	if (drop_only && edit_only)
+		option_conflict('d', 'e');
+	if (drop_only && edit_script_path)
+		option_conflict('d', 'F');
+	if (drop_only && fold_only)
+		option_conflict('d', 'f');
 	if (list_backups) {
 		if (abort_edit)
 			option_conflict('l', 'a');
@@ -12287,6 +12306,8 @@ cmd_histedit(int argc, char *argv[])
 			option_conflict('l', 'F');
 		if (edit_logmsg_only)
 			option_conflict('l', 'm');
+		if (drop_only)
+			option_conflict('l', 'd');
 		if (fold_only)
 			option_conflict('l', 'f');
 		if (edit_only)
@@ -12300,6 +12321,8 @@ cmd_histedit(int argc, char *argv[])
 			option_conflict('X', 'a');
 		if (continue_edit)
 			option_conflict('X', 'c');
+		if (drop_only)
+			option_conflict('X', 'd');
 		if (edit_script_path)
 			option_conflict('X', 'F');
 		if (edit_logmsg_only)
@@ -12405,6 +12428,13 @@ cmd_histedit(int argc, char *argv[])
 		    "before the -m option can be used");
 		goto done;
 	}
+	if (edit_in_progress && drop_only) {
+		error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
+		    "histedit operation is in progress in this "
+		    "work tree and must be continued or aborted "
+		    "before the -d option can be used");
+		goto done;
+	}
 	if (edit_in_progress && fold_only) {
 		error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
 		    "histedit operation is in progress in this "
@@ -12559,7 +12589,7 @@ cmd_histedit(int argc, char *argv[])
 				branch_name += 11;
 			error = histedit_edit_script(&histedit_cmds, &commits,
 			    branch_name, edit_logmsg_only, fold_only,
-			    edit_only, repo);
+			    drop_only, edit_only, repo);
 			if (error) {
 				got_worktree_histedit_abort(worktree, fileindex,
 				    repo, branch, base_commit_id,
blob - 25292e22c8c4a5b8c3fcc818735a1d79214c78e8
file + regress/cmdline/histedit.sh
--- regress/cmdline/histedit.sh
+++ regress/cmdline/histedit.sh
@@ -2308,6 +2308,122 @@ test_parseargs "$@"
 	test_done "$testroot" "$ret"
 }
 
+test_histedit_drop_only() {
+	local testroot=`test_init histedit_drop_only`
+
+	local orig_commit=`git_show_head $testroot/repo`
+	local drop="->  drop commit:"
+	local dropmsg="commit changes to drop"
+
+	echo "modified alpha on master" > $testroot/repo/alpha
+	(cd $testroot/repo && git rm -q beta)
+	echo "new file on master" > $testroot/repo/epsilon/new
+	(cd $testroot/repo && git add epsilon/new)
+
+	git_commit $testroot/repo -m "$dropmsg 1"
+	local drop_commit1=`git_show_head $testroot/repo`
+
+	echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+
+	git_commit $testroot/repo -m "$dropmsg 2"
+	local drop_commit2=`git_show_head $testroot/repo`
+
+	echo "modified delta on master" > $testroot/repo/gamma/delta
+
+	git_commit $testroot/repo -m "$dropmsg 3"
+	local drop_commit3=`git_show_head $testroot/repo`
+
+	got checkout -c $orig_commit $testroot/repo $testroot/wt > /dev/null
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got histedit -d > $testroot/stdout)
+	local new_commit1=`git_show_head $testroot/repo`
+
+	local short_commit1=`trim_obj_id 28 $drop_commit1`
+	local short_commit2=`trim_obj_id 28 $drop_commit2`
+	local short_commit3=`trim_obj_id 28 $drop_commit3`
+
+	echo "$short_commit1 $drop $dropmsg 1" > $testroot/stdout.expected
+	echo "$short_commit2 $drop $dropmsg 2" >> $testroot/stdout.expected
+	echo "$short_commit3 $drop $dropmsg 3" >> $testroot/stdout.expected
+	echo "Switching work tree to refs/heads/master" \
+		>> $testroot/stdout.expected
+
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "alpha" > $testroot/content.expected
+	cat $testroot/wt/alpha > $testroot/content
+	cmp -s $testroot/content.expected $testroot/content
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/content.expected $testroot/content
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "zeta" > $testroot/content.expected
+	cat $testroot/wt/epsilon/zeta > $testroot/content
+	cmp -s $testroot/content.expected $testroot/content
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/content.expected $testroot/content
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "delta" > $testroot/content.expected
+	cat $testroot/wt/gamma/delta > $testroot/content
+	cmp -s $testroot/content.expected $testroot/content
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/content.expected $testroot/content
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	if [ ! -e $testroot/wt/beta ]; then
+		echo "removed file beta should be restored" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+
+	if [ -e $testroot/wt/new ]; then
+		echo "new file should no longer exist" >&2
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got status > $testroot/stdout)
+
+	echo -n > $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got log | grep ^commit > $testroot/stdout)
+	echo "commit $orig_commit (master)" > $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
+	test_done "$testroot" "$ret"
+}
+
 test_parseargs "$@"
 run_test test_histedit_no_op
 run_test test_histedit_swap
@@ -2332,3 +2448,4 @@ run_test test_histedit_mesg_filemode_change
 run_test test_histedit_resets_committer
 run_test test_histedit_umask
 run_test test_histedit_mesg_filemode_change
+run_test test_histedit_drop_only

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