commit 5b87815ed2f346f81374261ce2d633feae711886 from: Stefan Sperling date: Thu Mar 05 11:20:24 2020 UTC prevent commits from being listed more than once in a histedit script While merging a commit multiple times during a histedit operation could potentially make sense in some corner case, a commit appearing more than once in the script is more likely to happen accidentally. If desired, the same effect can still be achieved by running multiple histedit operations, or by using 'got cherrypick' while the histedit operation is paused for arbitrary editing. commit - de05890fef951240ac68a3ea9a577a6f82be6194 commit + 5b87815ed2f346f81374261ce2d633feae711886 blob - ed10056f87241ad9aa4d28d8c5fc24f1fb04f15f blob + f5ab2f99e96290c4c84b883ead9e596fc5495130 --- got/got.1 +++ got/got.1 @@ -1098,6 +1098,7 @@ log message can be written. .Pp Every commit in the history being edited must be mentioned in the script. Lines may be re-ordered to change the order of commits in the edited history. +No commit may be listed more than once. .Pp Edited commits are accumulated on a temporary branch which the work tree will remain switched to throughout the entire histedit operation. blob - 3ac85b3f5be39dea43b8996068d4306f33a35769 blob + 16acb2621cdd21bffe0bafda2a0d4139eb8c1a0f --- got/got.c +++ got/got.c @@ -6082,7 +6082,7 @@ histedit_check_script(struct got_histedit_list *histed const struct got_error *err = NULL; struct got_object_qid *qid; struct got_histedit_list_entry *hle; - static char msg[80]; + static char msg[92]; char *id_str; if (TAILQ_EMPTY(histedit_cmds)) @@ -6090,6 +6090,24 @@ histedit_check_script(struct got_histedit_list *histed "histedit script contains no commands"); if (SIMPLEQ_EMPTY(commits)) return got_error(GOT_ERR_EMPTY_HISTEDIT); + + TAILQ_FOREACH(hle, histedit_cmds, entry) { + struct got_histedit_list_entry *hle2; + TAILQ_FOREACH(hle2, histedit_cmds, entry) { + if (hle == hle2) + continue; + if (got_object_id_cmp(hle->commit_id, + hle2->commit_id) != 0) + continue; + err = got_object_id_str(&id_str, hle->commit_id); + if (err) + return err; + snprintf(msg, sizeof(msg), "commit %s is listed " + "more than once in histedit script", id_str); + free(id_str); + return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg); + } + } SIMPLEQ_FOREACH(qid, commits, entry) { TAILQ_FOREACH(hle, histedit_cmds, entry) { blob - 11f94a58d35bcb17bf7b8b76dbac1f166171cc58 blob + d85840618184c07990545e7fc5f807ff54e29b6b --- regress/cmdline/histedit.sh +++ regress/cmdline/histedit.sh @@ -1284,7 +1284,58 @@ function test_histedit_split_commit { ret="$?" if [ "$ret" != "0" ]; then diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" + +} + +function test_histedit_duplicate_commit_in_script { + local testroot=`test_init histedit_duplicate_commit_in_script` + + local orig_commit=`git_show_head $testroot/repo` + + 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 "committing changes 1" + local old_commit1=`git_show_head $testroot/repo` + + echo "modified zeta on master" > $testroot/repo/epsilon/zeta + git_commit $testroot/repo -m "committing changes 2" + local old_commit2=`git_show_head $testroot/repo` + + got checkout -c $orig_commit $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + # This histedit script lists commit1 more than once + echo "p $old_commit1" > $testroot/histedit-script + echo "p $old_commit1" >> $testroot/histedit-script + echo "p $old_commit2" >> $testroot/histedit-script + + (cd $testroot/wt && got histedit -F $testroot/histedit-script \ + > $testroot/stdout 2> $testroot/stderr) + ret="$?" + if [ "$ret" == "0" ]; then + echo "histedit succeeded unexpectedly:" >&2 + cat $testroot/stdout >&2 + test_done "$testroot" "$ret" + return 1 fi + + echo -n "got: commit $old_commit1 is listed more than once " \ + > $testroot/stderr.expected + echo "in histedit script" >> $testroot/stderr.expected + + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + fi test_done "$testroot" "$ret" } @@ -1302,3 +1353,4 @@ run_test test_histedit_path_prefix_edit run_test test_histedit_outside_refs_heads run_test test_histedit_fold_last_commit_swap run_test test_histedit_split_commit +run_test test_histedit_duplicate_commit_in_script