commit - 839511b2e2ef1858aa18758d757677b5b8af7269
commit + c50a74557db04e5ab02a1b0c53cb4fbdd64088ac
blob - 237c161ab95271094fff0f6ca83316e7b1d60e7d
blob + 450e4baab5541257e9c371762a5fe893fa1c19bb
--- got/got.1
+++ got/got.1
.It Cm rb
Short alias for
.Cm rebase .
-.It Cm histedit Oo Fl a Oc Oo Fl c Oc Oo Fl f Oc Oo Fl F Ar histedit-script Oc Oo Fl m Oc Oo Fl l Oc Oo Fl X Oc Op Ar branch
+.It Cm histedit Oo Fl a Oc Oo Fl c Oc Oo Fl e Oc Oo Fl f Oc Oo Fl F Ar histedit-script Oc Oo Fl m Oc Oo Fl l Oc Oo Fl X Oc Op Ar branch
Edit commit history between the work tree's current base commit and
the tip commit of the work tree's current branch.
.Pp
.It Fl c
Continue an interrupted 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
+.Cm edit
+command for all commits.
+The
+.Fl e
+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 f
Fold all commits into a single commit.
This option is a quick equivalent to a histedit script which folds all
blob - a7a3f56bbcdf1e56c782beb4100d8d513f2ec999
blob + b375b79361d8973852cd690a8972093ca55267d0
--- got/got.c
+++ got/got.c
__dead static void
usage_histedit(void)
{
- fprintf(stderr, "usage: %s histedit [-a] [-c] [-f] "
+ fprintf(stderr, "usage: %s histedit [-a] [-c] [-e] [-f] "
"[-F histedit-script] [-m] [-l] [-X] [branch]\n",
getprogname());
exit(1);
static const struct got_error *
histedit_write_commit_list(struct got_object_id_queue *commits,
- FILE *f, int edit_logmsg_only, int fold_only, struct got_repository *repo)
+ FILE *f, int edit_logmsg_only, int fold_only, int edit_only,
+ struct got_repository *repo)
{
const struct got_error *err = NULL;
struct got_object_qid *qid;
STAILQ_FOREACH(qid, commits, entry) {
histedit_cmd = got_histedit_cmds[0].name;
- if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
+ if (edit_only)
+ histedit_cmd = "edit";
+ else if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
histedit_cmd = "fold";
err = histedit_write_commit(qid->id, histedit_cmd, f, repo);
if (err)
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, struct got_repository *repo)
+ int edit_logmsg_only, int fold_only, int edit_only,
+ struct got_repository *repo)
{
const struct got_error *err;
FILE *f = NULL;
goto done;
err = histedit_write_commit_list(commits, f, edit_logmsg_only,
- fold_only, repo);
+ fold_only, edit_only, repo);
if (err)
goto done;
- if (edit_logmsg_only || fold_only) {
+ if (edit_logmsg_only || fold_only || edit_only) {
rewind(f);
err = histedit_parse_list(histedit_cmds, f, repo);
} else {
} else if (resp == 'r') {
histedit_free_list(histedit_cmds);
err = histedit_edit_script(histedit_cmds,
- commits, branch_name, 0, 0, repo);
+ commits, branch_name, 0, 0, 0, repo);
if (err) {
if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
err->code != GOT_ERR_HISTEDIT_CMD)
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;
+ int 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;
TAILQ_INIT(&merged_paths);
memset(&upa, 0, sizeof(upa));
- while ((ch = getopt(argc, argv, "acfF:mlX")) != -1) {
+ while ((ch = getopt(argc, argv, "acefF:mlX")) != -1) {
switch (ch) {
case 'a':
abort_edit = 1;
case 'c':
continue_edit = 1;
break;
+ case 'e':
+ edit_only = 1;
+ break;
case 'f':
fold_only = 1;
break;
option_conflict('f', 'm');
if (edit_script_path && fold_only)
option_conflict('F', 'f');
+ if (abort_edit && edit_only)
+ option_conflict('a', 'e');
+ if (continue_edit && edit_only)
+ option_conflict('c', 'e');
+ if (edit_only && edit_logmsg_only)
+ option_conflict('e', 'm');
+ if (edit_script_path && edit_only)
+ option_conflict('F', 'e');
if (list_backups) {
if (abort_edit)
option_conflict('l', 'a');
option_conflict('l', 'm');
if (fold_only)
option_conflict('l', 'f');
+ if (edit_only)
+ option_conflict('l', 'e');
if (delete_backups)
option_conflict('l', 'X');
if (argc != 0 && argc != 1)
option_conflict('X', 'm');
if (fold_only)
option_conflict('X', 'f');
+ if (edit_only)
+ option_conflict('X', 'e');
if (list_backups)
option_conflict('X', 'l');
if (argc != 0 && argc != 1)
"before the -f option can be used");
goto done;
}
+ if (edit_in_progress && edit_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 -e option can be used");
+ goto done;
+ }
if (edit_in_progress && abort_edit) {
error = got_worktree_histedit_continue(&resume_commit_id,
if (strncmp(branch_name, "refs/heads/", 11) == 0)
branch_name += 11;
error = histedit_edit_script(&histedit_cmds, &commits,
- branch_name, edit_logmsg_only, fold_only, repo);
+ branch_name, edit_logmsg_only, fold_only,
+ edit_only, repo);
if (error) {
got_worktree_histedit_abort(worktree, fileindex,
repo, branch, base_commit_id,
blob - 24ae6d99cf14c28bd331ff1aebba74a90761a951
blob + ec9e48a654c56cc96e8bb36e57a8690cc98c76c0
--- regress/cmdline/histedit.sh
+++ regress/cmdline/histedit.sh
(cd $testroot/wt && got log | grep ^commit > $testroot/stdout)
echo "commit $new_commit1 (master)" > $testroot/stdout.expected
+ echo "commit $orig_commit" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+test_histedit_edit_only() {
+ local testroot=`test_init histedit_edit_only`
+
+ 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"
+ local old_commit1=`git_show_head $testroot/repo`
+
+ echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+ git_commit $testroot/repo -m "committing to zeta on master"
+ 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
+
+ (cd $testroot/wt && got histedit -e > $testroot/stdout)
+
+ local short_old_commit1=`trim_obj_id 28 $old_commit1`
+ local short_old_commit2=`trim_obj_id 28 $old_commit2`
+
+ echo "G alpha" > $testroot/stdout.expected
+ echo "D beta" >> $testroot/stdout.expected
+ echo "A epsilon/new" >> $testroot/stdout.expected
+ echo "Stopping histedit for amending commit $old_commit1" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "edited modified alpha on master" > $testroot/wt/alpha
+
+ cat > $testroot/editor.sh <<EOF
+#!/bin/sh
+sed -i 's/.*/committing edited changes 1/' "\$1"
+EOF
+ chmod +x $testroot/editor.sh
+
+ (cd $testroot/wt && env EDITOR="$testroot/editor.sh" \
+ VISUAL="$testroot/editor.sh" got histedit -c > $testroot/stdout)
+
+ local new_commit1=$(cd $testroot/wt && got info | \
+ grep '^work tree base commit: ' | cut -d: -f2 | tr -d ' ')
+ local short_new_commit1=`trim_obj_id 28 $new_commit1`
+
+ echo -n "$short_old_commit1 -> $short_new_commit1: " \
+ > $testroot/stdout.expected
+ echo "committing edited changes 1" >> $testroot/stdout.expected
+ echo "G epsilon/zeta" >> $testroot/stdout.expected
+ echo "Stopping histedit for amending commit $old_commit2" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "edited zeta on master" > $testroot/wt/epsilon/zeta
+
+ cat > $testroot/editor.sh <<EOF
+#!/bin/sh
+sed -i 's/.*/committing edited changes 2/' "\$1"
+EOF
+ chmod +x $testroot/editor.sh
+
+ (cd $testroot/wt && env EDITOR="$testroot/editor.sh" \
+ VISUAL="$testroot/editor.sh" got histedit -c > $testroot/stdout)
+
+ local new_commit2=`git_show_head $testroot/repo`
+ local short_new_commit2=`trim_obj_id 28 $new_commit2`
+
+ echo -n "$short_old_commit2 -> $short_new_commit2: " \
+ > $testroot/stdout.expected
+ echo "committing edited changes 2" >> $testroot/stdout.expected
+ echo "Switching work tree to refs/heads/master" \
+ >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "edited modified alpha on master" > $testroot/content.expected
+ cat $testroot/wt/alpha > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "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 still exists on disk" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "new file on master" > $testroot/content.expected
+ cat $testroot/wt/epsilon/new > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ 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" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got log -l3 | grep ^commit > $testroot/stdout)
+ echo "commit $new_commit2 (master)" > $testroot/stdout.expected
+ echo "commit $new_commit1" >> $testroot/stdout.expected
echo "commit $orig_commit" >> $testroot/stdout.expected
cmp -s $testroot/stdout.expected $testroot/stdout
ret="$?"
run_test test_histedit_fold_add_delete
run_test test_histedit_fold_only
run_test test_histedit_fold_only_empty_logmsg
+run_test test_histedit_edit_only