From: Mark Jamsek Subject: got histedit -d (drop all commits) To: Game of Trees Date: Tue, 31 Jan 2023 00:16:26 +1100 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 GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68