Commit Diff


commit - 3d1b16d126400e28a2cbab66b17dacd47a01763c
commit + acfd930bda7c65876653f0f2ad475436dc17ef9f
blob - 7a71eef0f01f4ba0d7203040a9f6ce7891dc108a
blob + 495bc5a1d44efc6d760792f0976a4cbf808e0b8a
--- Makefile.inc
+++ Makefile.inc
@@ -14,7 +14,6 @@ MANDIR ?= ${PREFIX}/man/man
 .else
 CFLAGS += -Werror -Wall -Wstrict-prototypes -Wmissing-prototypes
 CFLAGS += -Wwrite-strings -Wunused-variable
-CFLAGS += -Wno-unused-function
 PREFIX ?= ${HOME}
 BINDIR ?= ${PREFIX}/bin
 LIBEXECDIR ?= ${BINDIR}
blob - 12ab5c9682db9094d25525bc55e414088b2c75a8
blob + 1f51749ddf6911fb3d86837fa46e6565d991b44c
--- cvg/got.c
+++ cvg/got.c
@@ -95,7 +95,6 @@ struct got_cmd {
 __dead static void	usage(int, int);
 __dead static void	usage_import(void);
 __dead static void	usage_clone(void);
-__dead static void	usage_fetch(void);
 __dead static void	usage_checkout(void);
 __dead static void	usage_update(void);
 __dead static void	usage_log(void);
@@ -104,28 +103,19 @@ __dead static void	usage_blame(void);
 __dead static void	usage_tree(void);
 __dead static void	usage_status(void);
 __dead static void	usage_ref(void);
-__dead static void	usage_branch(void);
 __dead static void	usage_tag(void);
 __dead static void	usage_add(void);
 __dead static void	usage_remove(void);
 __dead static void	usage_patch(void);
 __dead static void	usage_revert(void);
 __dead static void	usage_commit(void);
-__dead static void	usage_send(void);
 __dead static void	usage_cherrypick(void);
 __dead static void	usage_backout(void);
-__dead static void	usage_rebase(void);
-__dead static void	usage_histedit(void);
-__dead static void	usage_integrate(void);
-__dead static void	usage_merge(void);
-__dead static void	usage_stage(void);
-__dead static void	usage_unstage(void);
 __dead static void	usage_cat(void);
 __dead static void	usage_info(void);
 
 static const struct got_error*		cmd_import(int, char *[]);
 static const struct got_error*		cmd_clone(int, char *[]);
-static const struct got_error*		cmd_fetch(int, char *[]);
 static const struct got_error*		cmd_checkout(int, char *[]);
 static const struct got_error*		cmd_update(int, char *[]);
 static const struct got_error*		cmd_log(int, char *[]);
@@ -134,29 +124,20 @@ static const struct got_error*		cmd_blame(int, char *[
 static const struct got_error*		cmd_tree(int, char *[]);
 static const struct got_error*		cmd_status(int, char *[]);
 static const struct got_error*		cmd_ref(int, char *[]);
-static const struct got_error*		cmd_branch(int, char *[]);
 static const struct got_error*		cmd_tag(int, char *[]);
 static const struct got_error*		cmd_add(int, char *[]);
 static const struct got_error*		cmd_remove(int, char *[]);
 static const struct got_error*		cmd_patch(int, char *[]);
 static const struct got_error*		cmd_revert(int, char *[]);
 static const struct got_error*		cmd_commit(int, char *[]);
-static const struct got_error*		cmd_send(int, char *[]);
 static const struct got_error*		cmd_cherrypick(int, char *[]);
 static const struct got_error*		cmd_backout(int, char *[]);
-static const struct got_error*		cmd_rebase(int, char *[]);
-static const struct got_error*		cmd_histedit(int, char *[]);
-static const struct got_error*		cmd_integrate(int, char *[]);
-static const struct got_error*		cmd_merge(int, char *[]);
-static const struct got_error*		cmd_stage(int, char *[]);
-static const struct got_error*		cmd_unstage(int, char *[]);
 static const struct got_error*		cmd_cat(int, char *[]);
 static const struct got_error*		cmd_info(int, char *[]);
 
 static const struct got_cmd got_commands[] = {
 	{ "import",	cmd_import,	usage_import,	"im" },
 	{ "clone",	cmd_clone,	usage_clone,	"cl" },
-	/*{ "fetch",	cmd_fetch,	usage_fetch,	"fe" },*/ /* rolled into update */
 	{ "checkout",	cmd_checkout,	usage_checkout,	"co" },
 	{ "update",	cmd_update,	usage_update,	"up" },
 	{ "log",	cmd_log,	usage_log,	"" },
@@ -165,22 +146,14 @@ static const struct got_cmd got_commands[] = {
 	{ "tree",	cmd_tree,	usage_tree,	"tr" },
 	{ "status",	cmd_status,	usage_status,	"st" },
 	{ "ref",	cmd_ref,	usage_ref,	"" },
-	/*{ "branch",	cmd_branch,	usage_branch,	"br" },*/
 	{ "tag",	cmd_tag,	usage_tag,	"" },
 	{ "add",	cmd_add,	usage_add,	"" },
 	{ "remove",	cmd_remove,	usage_remove,	"rm" },
 	{ "patch",	cmd_patch,	usage_patch,	"pa" },
 	{ "revert",	cmd_revert,	usage_revert,	"rv" },
 	{ "commit",	cmd_commit,	usage_commit,	"ci" },
-	/*{ "send",	cmd_send,	usage_send,	"se" },*/ /* part of commit */
 	{ "cherrypick",	cmd_cherrypick,	usage_cherrypick, "cy" },
 	{ "backout",	cmd_backout,	usage_backout,	"bo" },
-	/*{ "rebase",	cmd_rebase,	usage_rebase,	"rb" },*/
-	/*{ "histedit",	cmd_histedit,	usage_histedit,	"he" },*/
-	/*{ "integrate",  cmd_integrate,  usage_integrate,"ig" },*/
-	/*{ "merge",	cmd_merge,	usage_merge,	"mg" },*/
-	/*{ "stage",	cmd_stage,	usage_stage,	"sg" },*/
-	/*{ "unstage",	cmd_unstage,	usage_unstage,	"ug" },*/
 	{ "cat",	cmd_cat,	usage_cat,	"" },
 	{ "info",	cmd_info,	usage_info,	"" },
 };
@@ -1996,204 +1969,6 @@ done:
 }
 
 static const struct got_error *
-update_symref(const char *refname, struct got_reference *target_ref,
-    int verbosity, struct got_repository *repo)
-{
-	const struct got_error *err = NULL, *unlock_err;
-	struct got_reference *symref;
-	int symref_is_locked = 0;
-
-	err = got_ref_open(&symref, repo, refname, 1);
-	if (err) {
-		if (err->code != GOT_ERR_NOT_REF)
-			return err;
-		err = got_ref_alloc_symref(&symref, refname, target_ref);
-		if (err)
-			goto done;
-
-		err = got_ref_write(symref, repo);
-		if (err)
-			goto done;
-
-		if (verbosity >= 0)
-			printf("Created reference %s: %s\n",
-			    got_ref_get_name(symref),
-			    got_ref_get_symref_target(symref));
-	} else {
-		symref_is_locked = 1;
-
-		if (strcmp(got_ref_get_symref_target(symref),
-		    got_ref_get_name(target_ref)) == 0)
-			goto done;
-
-		err = got_ref_change_symref(symref,
-		    got_ref_get_name(target_ref));
-		if (err)
-			goto done;
-
-		err = got_ref_write(symref, repo);
-		if (err)
-			goto done;
-
-		if (verbosity >= 0)
-			printf("Updated %s: %s\n", got_ref_get_name(symref),
-			    got_ref_get_symref_target(symref));
-
-	}
-done:
-	if (symref_is_locked) {
-		unlock_err = got_ref_unlock(symref);
-		if (unlock_err && err == NULL)
-			err = unlock_err;
-	}
-	got_ref_close(symref);
-	return err;
-}
-
-__dead static void
-usage_fetch(void)
-{
-	fprintf(stderr, "usage: %s fetch [-adlqtvX] [-b branch] "
-	    "[-R reference] [-r repository-path] [remote-repository]\n",
-	    getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-delete_missing_ref(struct got_reference *ref,
-    int verbosity, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_object_id *id = NULL;
-	char *id_str = NULL;
-
-	if (got_ref_is_symbolic(ref)) {
-		err = got_ref_delete(ref, repo);
-		if (err)
-			return err;
-		if (verbosity >= 0) {
-			printf("Deleted %s: %s\n",
-			    got_ref_get_name(ref),
-			    got_ref_get_symref_target(ref));
-		}
-	} else {
-		err = got_ref_resolve(&id, repo, ref);
-		if (err)
-			return err;
-		err = got_object_id_str(&id_str, id);
-		if (err)
-			goto done;
-
-		err = got_ref_delete(ref, repo);
-		if (err)
-			goto done;
-		if (verbosity >= 0) {
-			printf("Deleted %s: %s\n",
-			    got_ref_get_name(ref), id_str);
-		}
-	}
-done:
-	free(id);
-	free(id_str);
-	return err;
-}
-
-static const struct got_error *
-delete_missing_refs(struct got_pathlist_head *their_refs,
-    struct got_pathlist_head *their_symrefs,
-    const struct got_remote_repo *remote,
-    int verbosity, struct got_repository *repo)
-{
-	const struct got_error *err = NULL, *unlock_err;
-	struct got_reflist_head my_refs;
-	struct got_reflist_entry *re;
-	struct got_pathlist_entry *pe;
-	char *remote_namespace = NULL;
-	char *local_refname = NULL;
-
-	TAILQ_INIT(&my_refs);
-
-	if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
-	    == -1)
-		return got_error_from_errno("asprintf");
-
-	err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
-	if (err)
-		goto done;
-
-	TAILQ_FOREACH(re, &my_refs, entry) {
-		const char *refname = got_ref_get_name(re->ref);
-		const char *their_refname;
-
-		if (remote->mirror_references) {
-			their_refname = refname;
-		} else {
-			if (strncmp(refname, remote_namespace,
-			    strlen(remote_namespace)) == 0) {
-				if (strcmp(refname + strlen(remote_namespace),
-				    GOT_REF_HEAD) == 0)
-					continue;
-				if (asprintf(&local_refname, "refs/heads/%s",
-				    refname + strlen(remote_namespace)) == -1) {
-					err = got_error_from_errno("asprintf");
-					goto done;
-				}
-			} else if (strncmp(refname, "refs/tags/", 10) != 0)
-				continue;
-
-			their_refname = local_refname;
-		}
-
-		TAILQ_FOREACH(pe, their_refs, entry) {
-			if (strcmp(their_refname, pe->path) == 0)
-				break;
-		}
-		if (pe != NULL)
-			continue;
-
-		TAILQ_FOREACH(pe, their_symrefs, entry) {
-			if (strcmp(their_refname, pe->path) == 0)
-				break;
-		}
-		if (pe != NULL)
-			continue;
-
-		err = delete_missing_ref(re->ref, verbosity, repo);
-		if (err)
-			break;
-
-		if (local_refname) {
-			struct got_reference *ref;
-			err = got_ref_open(&ref, repo, local_refname, 1);
-			if (err) {
-				if (err->code != GOT_ERR_NOT_REF)
-					break;
-				free(local_refname);
-				local_refname = NULL;
-				continue;
-			}
-			err = delete_missing_ref(ref, verbosity, repo);
-			if (err)
-				break;
-			unlock_err = got_ref_unlock(ref);
-			got_ref_close(ref);
-			if (unlock_err && err == NULL) {
-				err = unlock_err;
-				break;
-			}
-
-			free(local_refname);
-			local_refname = NULL;
-		}
-	}
-done:
-	got_ref_list_free(&my_refs);
-	free(remote_namespace);
-	free(local_refname);
-	return err;
-}
-
-static const struct got_error *
 update_wanted_ref(const char *refname, struct got_object_id *id,
     const char *remote_repo_name, int verbosity, struct got_repository *repo)
 {
@@ -2256,33 +2031,6 @@ done:
 	return err;
 }
 
-static const struct got_error *
-delete_refs_for_remote(struct got_repository *repo, const char *remote_name)
-{
-	const struct got_error *err = NULL;
-	struct got_reflist_head refs;
-	struct got_reflist_entry *re;
-	char *prefix;
-
-	TAILQ_INIT(&refs);
-
-	if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) {
-		err = got_error_from_errno("asprintf");
-		goto done;
-	}
-	err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL);
-	if (err)
-		goto done;
-
-	TAILQ_FOREACH(re, &refs, entry)
-		delete_ref(repo, re->ref);
-done:
-	got_ref_list_free(&refs);
-	return err;
-}
-
-
-
 __dead static void
 usage_checkout(void)
 {
@@ -2805,46 +2553,6 @@ update_progress(void *arg, unsigned char status, const
 }
 
 static const struct got_error *
-switch_head_ref(struct got_reference *head_ref,
-    struct got_object_id *commit_id, struct got_worktree *worktree,
-    struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	char *base_id_str;
-	int ref_has_moved = 0;
-
-	/* Trivial case: switching between two different references. */
-	if (strcmp(got_ref_get_name(head_ref),
-	    got_worktree_get_head_ref_name(worktree)) != 0) {
-		printf("Switching work tree from %s to %s\n",
-		    got_worktree_get_head_ref_name(worktree),
-		    got_ref_get_name(head_ref));
-		return got_worktree_set_head_ref(worktree, head_ref);
-	}
-
-	err = check_linear_ancestry(commit_id,
-	    got_worktree_get_base_commit_id(worktree), 0, repo);
-	if (err) {
-		if (err->code != GOT_ERR_ANCESTRY)
-			return err;
-		ref_has_moved = 1;
-	}
-	if (!ref_has_moved)
-		return NULL;
-
-	/* Switching to a rebased branch with the same reference name. */
-	err = got_object_id_str(&base_id_str,
-	    got_worktree_get_base_commit_id(worktree));
-	if (err)
-		return err;
-	printf("Reference %s now points at a different branch\n",
-	    got_worktree_get_head_ref_name(worktree));
-	printf("Switching work tree from %s to %s\n", base_id_str,
-	    got_worktree_get_head_ref_name(worktree));
-	return NULL;
-}
-
-static const struct got_error *
 check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
 {
 	const struct got_error *err;
@@ -6399,447 +6107,6 @@ done:
 }
 
 __dead static void
-usage_branch(void)
-{
-	fprintf(stderr, "usage: %s branch [-lnt] [-c commit] [-d name] "
-	    "[-r repository-path] [name]\n", getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-list_branch(struct got_repository *repo, struct got_worktree *worktree,
-    struct got_reference *ref)
-{
-	const struct got_error *err = NULL;
-	const char *refname, *marker = "  ";
-	char *refstr;
-
-	refname = got_ref_get_name(ref);
-	if (worktree && strcmp(refname,
-	    got_worktree_get_head_ref_name(worktree)) == 0) {
-		struct got_object_id *id = NULL;
-
-		err = got_ref_resolve(&id, repo, ref);
-		if (err)
-			return err;
-		if (got_object_id_cmp(id,
-		    got_worktree_get_base_commit_id(worktree)) == 0)
-			marker = "* ";
-		else
-			marker = "~ ";
-		free(id);
-	}
-
-	if (strncmp(refname, "refs/heads/", 11) == 0)
-		refname += 11;
-	if (strncmp(refname, "refs/got/worktree/", 18) == 0)
-		refname += 18;
-	if (strncmp(refname, "refs/remotes/", 13) == 0)
-		refname += 13;
-
-	refstr = got_ref_to_str(ref);
-	if (refstr == NULL)
-		return got_error_from_errno("got_ref_to_str");
-
-	printf("%s%s: %s\n", marker, refname, refstr);
-	free(refstr);
-	return NULL;
-}
-
-static const struct got_error *
-show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
-{
-	const char *refname;
-
-	if (worktree == NULL)
-		return got_error(GOT_ERR_NOT_WORKTREE);
-
-	refname = got_worktree_get_head_ref_name(worktree);
-
-	if (strncmp(refname, "refs/heads/", 11) == 0)
-		refname += 11;
-	if (strncmp(refname, "refs/got/worktree/", 18) == 0)
-		refname += 18;
-
-	printf("%s\n", refname);
-
-	return NULL;
-}
-
-static const struct got_error *
-list_branches(struct got_repository *repo, struct got_worktree *worktree,
-    int sort_by_time)
-{
-	static const struct got_error *err = NULL;
-	struct got_reflist_head refs;
-	struct got_reflist_entry *re;
-	struct got_reference *temp_ref = NULL;
-	int rebase_in_progress, histedit_in_progress;
-
-	TAILQ_INIT(&refs);
-
-	if (worktree) {
-		err = got_worktree_rebase_in_progress(&rebase_in_progress,
-		    worktree);
-		if (err)
-			return err;
-
-		err = got_worktree_histedit_in_progress(&histedit_in_progress,
-		    worktree);
-		if (err)
-			return err;
-
-		if (rebase_in_progress || histedit_in_progress) {
-			err = got_ref_open(&temp_ref, repo,
-			    got_worktree_get_head_ref_name(worktree), 0);
-			if (err)
-				return err;
-			list_branch(repo, worktree, temp_ref);
-			got_ref_close(temp_ref);
-		}
-	}
-
-	err = got_ref_list(&refs, repo, "refs/heads", sort_by_time ?
-	    got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
-	    repo);
-	if (err)
-		return err;
-
-	TAILQ_FOREACH(re, &refs, entry)
-		list_branch(repo, worktree, re->ref);
-
-	got_ref_list_free(&refs);
-
-	err = got_ref_list(&refs, repo, "refs/remotes", sort_by_time ?
-	    got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
-	    repo);
-	if (err)
-		return err;
-
-	TAILQ_FOREACH(re, &refs, entry)
-		list_branch(repo, worktree, re->ref);
-
-	got_ref_list_free(&refs);
-
-	return NULL;
-}
-
-static const struct got_error *
-delete_branch(struct got_repository *repo, struct got_worktree *worktree,
-    const char *branch_name)
-{
-	const struct got_error *err = NULL;
-	struct got_reference *ref = NULL;
-	char *refname, *remote_refname = NULL;
-
-	if (strncmp(branch_name, "refs/", 5) == 0)
-		branch_name += 5;
-	if (strncmp(branch_name, "heads/", 6) == 0)
-		branch_name += 6;
-	else if (strncmp(branch_name, "remotes/", 8) == 0)
-		branch_name += 8;
-
-	if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
-		return got_error_from_errno("asprintf");
-
-	if (asprintf(&remote_refname, "refs/remotes/%s",
-	    branch_name) == -1) {
-		err = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	err = got_ref_open(&ref, repo, refname, 0);
-	if (err) {
-		const struct got_error *err2;
-		if (err->code != GOT_ERR_NOT_REF)
-			goto done;
-		/*
-		 * Keep 'err' intact such that if neither branch exists
-		 * we report "refs/heads" rather than "refs/remotes" in
-		 * our error message.
-		 */
-		err2 = got_ref_open(&ref, repo, remote_refname, 0);
-		if (err2)
-			goto done;
-		err = NULL;
-	}
-
-	if (worktree &&
-	    strcmp(got_worktree_get_head_ref_name(worktree),
-	    got_ref_get_name(ref)) == 0) {
-		err = got_error_msg(GOT_ERR_SAME_BRANCH,
-		    "will not delete this work tree's current branch");
-		goto done;
-	}
-
-	err = delete_ref(repo, ref);
-done:
-	if (ref)
-		got_ref_close(ref);
-	free(refname);
-	free(remote_refname);
-	return err;
-}
-
-static const struct got_error *
-add_branch(struct got_repository *repo, const char *branch_name,
-    struct got_object_id *base_commit_id)
-{
-	const struct got_error *err = NULL;
-	struct got_reference *ref = NULL;
-	char *refname = NULL;
-
-	/*
-	 * Don't let the user create a branch name with a leading '-'.
-	 * While technically a valid reference name, this case is usually
-	 * an unintended typo.
-	 */
-	if (branch_name[0] == '-')
-		return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
-
-	if (strncmp(branch_name, "refs/heads/", 11) == 0)
-		branch_name += 11;
-
-	if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
-		err = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	err = got_ref_open(&ref, repo, refname, 0);
-	if (err == NULL) {
-		err = got_error(GOT_ERR_BRANCH_EXISTS);
-		goto done;
-	} else if (err->code != GOT_ERR_NOT_REF)
-		goto done;
-
-	err = got_ref_alloc(&ref, refname, base_commit_id);
-	if (err)
-		goto done;
-
-	err = got_ref_write(ref, repo);
-done:
-	if (ref)
-		got_ref_close(ref);
-	free(refname);
-	return err;
-}
-
-static const struct got_error *
-cmd_branch(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_repository *repo = NULL;
-	struct got_worktree *worktree = NULL;
-	char *cwd = NULL, *repo_path = NULL;
-	int ch, do_list = 0, do_show = 0, do_update = 1, sort_by_time = 0;
-	const char *delref = NULL, *commit_id_arg = NULL;
-	struct got_reference *ref = NULL;
-	struct got_pathlist_head paths;
-	struct got_object_id *commit_id = NULL;
-	char *commit_id_str = NULL;
-	int *pack_fds = NULL;
-
-	TAILQ_INIT(&paths);
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec "
-	    "sendfd unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "c:d:lnr:t")) != -1) {
-		switch (ch) {
-		case 'c':
-			commit_id_arg = optarg;
-			break;
-		case 'd':
-			delref = optarg;
-			break;
-		case 'l':
-			do_list = 1;
-			break;
-		case 'n':
-			do_update = 0;
-			break;
-		case 'r':
-			repo_path = realpath(optarg, NULL);
-			if (repo_path == NULL)
-				return got_error_from_errno2("realpath",
-				    optarg);
-			got_path_strip_trailing_slashes(repo_path);
-			break;
-		case 't':
-			sort_by_time = 1;
-			break;
-		default:
-			usage_branch();
-			/* NOTREACHED */
-		}
-	}
-
-	if (do_list && delref)
-		option_conflict('l', 'd');
-	if (sort_by_time && !do_list)
-		errx(1, "-t option requires -l option");
-
-	argc -= optind;
-	argv += optind;
-
-	if (!do_list && !delref && argc == 0)
-		do_show = 1;
-
-	if ((do_list || delref || do_show) && commit_id_arg != NULL)
-		errx(1, "-c option can only be used when creating a branch");
-
-	if (do_list || delref) {
-		if (argc > 0)
-			usage_branch();
-	} else if (!do_show && argc != 1)
-		usage_branch();
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (repo_path == NULL) {
-		error = got_worktree_open(&worktree, cwd);
-		if (error && error->code != GOT_ERR_NOT_WORKTREE)
-			goto done;
-		else
-			error = NULL;
-		if (worktree) {
-			repo_path =
-			    strdup(got_worktree_get_repo_path(worktree));
-			if (repo_path == NULL)
-				error = got_error_from_errno("strdup");
-			if (error)
-				goto done;
-		} else {
-			repo_path = strdup(cwd);
-			if (repo_path == NULL) {
-				error = got_error_from_errno("strdup");
-				goto done;
-			}
-		}
-	}
-
-	error = got_repo_open(&repo, repo_path, NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-#ifndef PROFILE
-	if (do_list || do_show) {
-		/* Remove "cpath" promise. */
-		if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
-		    NULL) == -1)
-			err(1, "pledge");
-	}
-#endif
-
-	error = apply_unveil(got_repo_get_path(repo), do_list,
-	    worktree ? got_worktree_get_root_path(worktree) : NULL);
-	if (error)
-		goto done;
-
-	if (do_show)
-		error = show_current_branch(repo, worktree);
-	else if (do_list)
-		error = list_branches(repo, worktree, sort_by_time);
-	else if (delref)
-		error = delete_branch(repo, worktree, delref);
-	else {
-		struct got_reflist_head refs;
-		TAILQ_INIT(&refs);
-		error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
-		    NULL);
-		if (error)
-			goto done;
-		if (commit_id_arg == NULL)
-			commit_id_arg = worktree ?
-			    got_worktree_get_head_ref_name(worktree) :
-			    GOT_REF_HEAD;
-		error = got_repo_match_object_id(&commit_id, NULL,
-		    commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo);
-		got_ref_list_free(&refs);
-		if (error)
-			goto done;
-		error = add_branch(repo, argv[0], commit_id);
-		if (error)
-			goto done;
-		if (worktree && do_update) {
-			struct got_update_progress_arg upa;
-			char *branch_refname = NULL;
-
-			error = got_object_id_str(&commit_id_str, commit_id);
-			if (error)
-				goto done;
-			error = get_worktree_paths_from_argv(&paths, 0, NULL,
-			    worktree);
-			if (error)
-				goto done;
-			if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
-			    == -1) {
-				error = got_error_from_errno("asprintf");
-				goto done;
-			}
-			error = got_ref_open(&ref, repo, branch_refname, 0);
-			free(branch_refname);
-			if (error)
-				goto done;
-			error = switch_head_ref(ref, commit_id, worktree,
-			    repo);
-			if (error)
-				goto done;
-			error = got_worktree_set_base_commit_id(worktree, repo,
-			    commit_id);
-			if (error)
-				goto done;
-			memset(&upa, 0, sizeof(upa));
-			error = got_worktree_checkout_files(worktree, &paths,
-			    repo, update_progress, &upa, check_cancelled,
-			    NULL);
-			if (error)
-				goto done;
-			if (upa.did_something) {
-				printf("Updated to %s: %s\n",
-				    got_worktree_get_head_ref_name(worktree),
-				    commit_id_str);
-			}
-			print_update_progress_stats(&upa);
-		}
-	}
-done:
-	if (ref)
-		got_ref_close(ref);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (worktree)
-		got_worktree_close(worktree);
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	free(cwd);
-	free(repo_path);
-	free(commit_id);
-	free(commit_id_str);
-	got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
-	return error;
-}
-
-
-__dead static void
 usage_tag(void)
 {
 	fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] "
@@ -9132,4414 +8399,514 @@ done:
 	return error;
 }
 
-__dead static void
-usage_send(void)
+/*
+ * Print and if delete is set delete all ref_prefix references.
+ * If wanted_ref is not NULL, only print or delete this reference.
+ */
+static const struct got_error *
+process_logmsg_refs(const char *ref_prefix, size_t prefix_len,
+    const char *wanted_ref, int delete, struct got_worktree *worktree,
+    struct got_repository *repo)
 {
-	fprintf(stderr, "usage: %s send [-afqTv] [-b branch] [-d branch] "
-	    "[-r repository-path] [-t tag] [remote-repository]\n",
-	    getprogname());
-	exit(1);
-}
+	const struct got_error			*err;
+	struct got_pathlist_head		 paths;
+	struct got_reflist_head			 refs;
+	struct got_reflist_entry		*re;
+	struct got_reflist_object_id_map	*refs_idmap = NULL;
+	struct got_commit_object		*commit = NULL;
+	struct got_object_id			*id = NULL;
+	const char				*header_prefix;
+	char					*uuidstr = NULL;
+	int					 found = 0;
 
-static void
-print_load_info(int print_colored, int print_found, int print_trees,
-    int ncolored, int nfound, int ntrees)
-{
-	if (print_colored) {
-		printf("%d commit%s colored", ncolored,
-		    ncolored == 1 ? "" : "s");
-	}
-	if (print_found) {
-		printf("%s%d object%s found",
-		    ncolored > 0 ? "; " : "",
-		    nfound, nfound == 1 ? "" : "s");
-	}
-	if (print_trees) {
-		printf("; %d tree%s scanned", ntrees,
-		    ntrees == 1 ? "" : "s");
-	}
-}
+	TAILQ_INIT(&refs);
+	TAILQ_INIT(&paths);
 
-struct got_send_progress_arg {
-	char last_scaled_packsize[FMT_SCALED_STRSIZE];
-	int verbosity;
-	int last_ncolored;
-	int last_nfound;
-	int last_ntrees;
-	int loading_done;
-	int last_ncommits;
-	int last_nobj_total;
-	int last_p_deltify;
-	int last_p_written;
-	int last_p_sent;
-	int printed_something;
-	int sent_something;
-	struct got_pathlist_head *delete_branches;
-};
+	err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo);
+	if (err)
+		goto done;
 
-static const struct got_error *
-send_progress(void *arg, int ncolored, int nfound, int ntrees,
-    off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify,
-    int nobj_written, off_t bytes_sent, const char *refname,
-    const char *errmsg, int success)
-{
-	struct got_send_progress_arg *a = arg;
-	char scaled_packsize[FMT_SCALED_STRSIZE];
-	char scaled_sent[FMT_SCALED_STRSIZE];
-	int p_deltify = 0, p_written = 0, p_sent = 0;
-	int print_colored = 0, print_found = 0, print_trees = 0;
-	int print_searching = 0, print_total = 0;
-	int print_deltify = 0, print_written = 0, print_sent = 0;
+	err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
+	if (err)
+		goto done;
 
-	if (a->verbosity < 0)
-		return NULL;
+	if (worktree != NULL) {
+		err = got_worktree_get_uuid(&uuidstr, worktree);
+		if (err)
+			goto done;
+	}
 
-	if (refname) {
-		const char *status = success ? "accepted" : "rejected";
+	if (wanted_ref) {
+		if (strncmp(wanted_ref, "refs/heads/", 11) == 0)
+			wanted_ref += 11;
+	}
 
-		if (success) {
-			struct got_pathlist_entry *pe;
-			TAILQ_FOREACH(pe, a->delete_branches, entry) {
-				const char *branchname = pe->path;
-				if (got_path_cmp(branchname, refname,
-				    strlen(branchname), strlen(refname)) == 0) {
-					status = "deleted";
-					a->sent_something = 1;
-					break;
-				}
-			}
-		}
+	if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0)
+		header_prefix = "backout";
+	else
+		header_prefix = "cherrypick";
 
-		if (a->printed_something)
-			putchar('\n');
-		printf("Server has %s %s", status, refname);
-		if (errmsg)
-			printf(": %s", errmsg);
-		a->printed_something = 1;
-		return NULL;
-	}
+	TAILQ_FOREACH(re, &refs, entry) {
+		const char *refname, *wt;
 
-	if (a->last_ncolored != ncolored) {
-		print_colored = 1;
-		a->last_ncolored = ncolored;
-	}
+		refname = got_ref_get_name(re->ref);
 
-	if (a->last_nfound != nfound) {
-		print_colored = 1;
-		print_found = 1;
-		a->last_nfound = nfound;
-	}
+		err = check_cancelled(NULL);
+		if (err)
+			goto done;
 
-	if (a->last_ntrees != ntrees) {
-		print_colored = 1;
-		print_found = 1;
-		print_trees = 1;
-		a->last_ntrees = ntrees;
-	}
+		if (strncmp(refname, ref_prefix, prefix_len) == 0)
+			refname += prefix_len + 1;  /* skip '-' delimiter */
+		else
+			continue;
 
-	if ((print_colored || print_found || print_trees) &&
-	    !a->loading_done) {
-		printf("\r");
-		print_load_info(print_colored, print_found, print_trees,
-		    ncolored, nfound, ntrees);
-		a->printed_something = 1;
-		fflush(stdout);
-		return NULL;
-	} else if (!a->loading_done) {
-		printf("\r");
-		print_load_info(1, 1, 1, ncolored, nfound, ntrees);
-		printf("\n");
-		a->loading_done = 1;
-	}
+		wt = refname;
 
-	if (fmt_scaled(packfile_size, scaled_packsize) == -1)
-		return got_error_from_errno("fmt_scaled");
-	if (fmt_scaled(bytes_sent, scaled_sent) == -1)
-		return got_error_from_errno("fmt_scaled");
+		if (worktree == NULL || strncmp(refname, uuidstr,
+		    GOT_WORKTREE_UUID_STRLEN) == 0)
+			refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
+		else
+			continue;
 
-	if (a->last_ncommits != ncommits) {
-		print_searching = 1;
-		a->last_ncommits = ncommits;
-	}
+		err = got_repo_match_object_id(&id, NULL, refname,
+		    GOT_OBJ_TYPE_COMMIT, NULL, repo);
+		if (err)
+			goto done;
 
-	if (a->last_nobj_total != nobj_total) {
-		print_searching = 1;
-		print_total = 1;
-		a->last_nobj_total = nobj_total;
-	}
+		err = got_object_open_as_commit(&commit, repo, id);
+		if (err)
+			goto done;
 
-	if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' ||
-	    strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) {
-		if (strlcpy(a->last_scaled_packsize, scaled_packsize,
-		    FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
-			return got_error(GOT_ERR_NO_SPACE);
-	}
+		if (wanted_ref)
+			found = strncmp(wanted_ref, refname,
+			    strlen(wanted_ref)) == 0;
+		if (wanted_ref && !found) {
+			struct got_reflist_head	*ci_refs;
 
-	if (nobj_deltify > 0 || nobj_written > 0) {
-		if (nobj_deltify > 0) {
-			p_deltify = (nobj_deltify * 100) / nobj_total;
-			if (p_deltify != a->last_p_deltify) {
-				a->last_p_deltify = p_deltify;
-				print_searching = 1;
-				print_total = 1;
-				print_deltify = 1;
+			ci_refs = got_reflist_object_id_map_lookup(refs_idmap,
+			    id);
+
+			if (ci_refs) {
+				char		*refs_str = NULL;
+				char const	*r = NULL;
+
+				err = build_refs_str(&refs_str, ci_refs, id,
+				    repo, 1);
+				if (err)
+					goto done;
+
+				r = refs_str;
+				while (r) {
+					if (strncmp(r, wanted_ref,
+					    strlen(wanted_ref)) == 0) {
+						found = 1;
+						break;
+					}
+					r = strchr(r, ' ');
+					if (r)
+						++r;
+				}
+				free(refs_str);
 			}
 		}
-		if (nobj_written > 0) {
-			p_written = (nobj_written * 100) / nobj_total;
-			if (p_written != a->last_p_written) {
-				a->last_p_written = p_written;
-				print_searching = 1;
-				print_total = 1;
-				print_deltify = 1;
-				print_written = 1;
+
+		if (wanted_ref == NULL || found) {
+			if (delete) {
+				err = got_ref_delete(re->ref, repo);
+				if (err)
+					goto done;
+				printf("Deleted: ");
+				err = print_commit_oneline(commit, id, repo,
+				    refs_idmap);
+			} else {
+				/*
+				 * Print paths modified by commit to help
+				 * associate commits with worktree changes.
+				 */
+				err = get_changed_paths(&paths, commit,
+				    repo, NULL);
+				if (err)
+					goto done;
+
+				err = print_commit(commit, id, repo, NULL,
+				    &paths, NULL, 0, 0, refs_idmap, NULL,
+				    header_prefix);
+				got_pathlist_free(&paths,
+				    GOT_PATHLIST_FREE_ALL);
+
+				if (worktree == NULL)
+					printf("work tree: %.*s\n\n",
+					    GOT_WORKTREE_UUID_STRLEN, wt);
 			}
+			if (err || found)
+				goto done;
 		}
-	}
 
-	if (bytes_sent > 0) {
-		p_sent = (bytes_sent * 100) / packfile_size;
-		if (p_sent != a->last_p_sent) {
-			a->last_p_sent = p_sent;
-			print_searching = 1;
-			print_total = 1;
-			print_deltify = 1;
-			print_written = 1;
-			print_sent = 1;
-		}
-		a->sent_something = 1;
+		got_object_commit_close(commit);
+		commit = NULL;
+		free(id);
+		id = NULL;
 	}
 
-	if (print_searching || print_total || print_deltify || print_written ||
-	    print_sent)
-		printf("\r");
-	if (print_searching)
-		printf("packing %d reference%s", ncommits,
-		    ncommits == 1 ? "" : "s");
-	if (print_total)
-		printf("; %d object%s", nobj_total,
-		    nobj_total == 1 ? "" : "s");
-	if (print_deltify)
-		printf("; deltify: %d%%", p_deltify);
-	if (print_sent)
-		printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
-		    scaled_packsize, p_sent);
-	else if (print_written)
-		printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
-		    scaled_packsize, p_written);
-	if (print_searching || print_total || print_deltify ||
-	    print_written || print_sent) {
-		a->printed_something = 1;
-		fflush(stdout);
-	}
-	return NULL;
-}
-
-static const struct got_error *
-cmd_send(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	char *cwd = NULL, *repo_path = NULL;
-	const char *remote_name;
-	char *proto = NULL, *host = NULL, *port = NULL;
-	char *repo_name = NULL, *server_path = NULL;
-	const struct got_remote_repo *remotes, *remote = NULL;
-	int nremotes, nbranches = 0, ndelete_branches = 0;
-	struct got_repository *repo = NULL;
-	struct got_worktree *worktree = NULL;
-	const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
-	struct got_pathlist_head branches;
-	struct got_pathlist_head tags;
-	struct got_reflist_head all_branches;
-	struct got_reflist_head all_tags;
-	struct got_pathlist_head delete_args;
-	struct got_pathlist_head delete_branches;
-	struct got_reflist_entry *re;
-	struct got_pathlist_entry *pe;
-	int i, ch, sendfd = -1, sendstatus;
-	pid_t sendpid = -1;
-	struct got_send_progress_arg spa;
-	int verbosity = 0, overwrite_refs = 0;
-	int send_all_branches = 0, send_all_tags = 0;
-	struct got_reference *ref = NULL;
-	int *pack_fds = NULL;
-
-	TAILQ_INIT(&branches);
-	TAILQ_INIT(&tags);
-	TAILQ_INIT(&all_branches);
-	TAILQ_INIT(&all_tags);
-	TAILQ_INIT(&delete_args);
-	TAILQ_INIT(&delete_branches);
-
-	while ((ch = getopt(argc, argv, "ab:d:fqr:Tt:v")) != -1) {
-		switch (ch) {
-		case 'a':
-			send_all_branches = 1;
-			break;
-		case 'b':
-			error = got_pathlist_append(&branches, optarg, NULL);
-			if (error)
-				return error;
-			nbranches++;
-			break;
-		case 'd':
-			error = got_pathlist_append(&delete_args, optarg, NULL);
-			if (error)
-				return error;
-			break;
-		case 'f':
-			overwrite_refs = 1;
-			break;
-		case 'q':
-			verbosity = -1;
-			break;
-		case 'r':
-			repo_path = realpath(optarg, NULL);
-			if (repo_path == NULL)
-				return got_error_from_errno2("realpath",
-				    optarg);
-			got_path_strip_trailing_slashes(repo_path);
-			break;
-		case 'T':
-			send_all_tags = 1;
-			break;
-		case 't':
-			error = got_pathlist_append(&tags, optarg, NULL);
-			if (error)
-				return error;
-			break;
-		case 'v':
-			if (verbosity < 0)
-				verbosity = 0;
-			else if (verbosity < 3)
-				verbosity++;
-			break;
-		default:
-			usage_send();
-			/* NOTREACHED */
-		}
-	}
-	argc -= optind;
-	argv += optind;
-
-	if (send_all_branches && !TAILQ_EMPTY(&branches))
-		option_conflict('a', 'b');
-	if (send_all_tags && !TAILQ_EMPTY(&tags))
-		option_conflict('T', 't');
-
-
-	if (argc == 0)
-		remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
-	else if (argc == 1)
-		remote_name = argv[0];
-	else
-		usage_send();
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (repo_path == NULL) {
-		error = got_worktree_open(&worktree, cwd);
-		if (error && error->code != GOT_ERR_NOT_WORKTREE)
-			goto done;
-		else
-			error = NULL;
-		if (worktree) {
-			repo_path =
-			    strdup(got_worktree_get_repo_path(worktree));
-			if (repo_path == NULL)
-				error = got_error_from_errno("strdup");
-			if (error)
-				goto done;
-		} else {
-			repo_path = strdup(cwd);
-			if (repo_path == NULL) {
-				error = got_error_from_errno("strdup");
-				goto done;
-			}
-		}
-	}
-
-	error = got_repo_open(&repo, repo_path, NULL, pack_fds);
-	if (error)
-		goto done;
-
-	if (worktree) {
-		worktree_conf = got_worktree_get_gotconfig(worktree);
-		if (worktree_conf) {
-			got_gotconfig_get_remotes(&nremotes, &remotes,
-			    worktree_conf);
-			for (i = 0; i < nremotes; i++) {
-				if (strcmp(remotes[i].name, remote_name) == 0) {
-					remote = &remotes[i];
-					break;
-				}
-			}
-		}
-	}
-	if (remote == NULL) {
-		repo_conf = got_repo_get_gotconfig(repo);
-		if (repo_conf) {
-			got_gotconfig_get_remotes(&nremotes, &remotes,
-			    repo_conf);
-			for (i = 0; i < nremotes; i++) {
-				if (strcmp(remotes[i].name, remote_name) == 0) {
-					remote = &remotes[i];
-					break;
-				}
-			}
-		}
-	}
-	if (remote == NULL) {
-		got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
-		for (i = 0; i < nremotes; i++) {
-			if (strcmp(remotes[i].name, remote_name) == 0) {
-				remote = &remotes[i];
-				break;
-			}
-		}
-	}
-	if (remote == NULL) {
-		error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
-		goto done;
-	}
-
-	error = got_dial_parse_uri(&proto, &host, &port, &server_path,
-	    &repo_name, remote->send_url);
-	if (error)
-		goto done;
-
-	if (strcmp(proto, "git") == 0) {
-#ifndef PROFILE
-		if (pledge("stdio rpath wpath cpath fattr flock proc exec "
-		    "sendfd dns inet unveil", NULL) == -1)
-			err(1, "pledge");
-#endif
-	} else if (strcmp(proto, "git+ssh") == 0 ||
-	    strcmp(proto, "ssh") == 0) {
-#ifndef PROFILE
-		if (pledge("stdio rpath wpath cpath fattr flock proc exec "
-		    "sendfd unveil", NULL) == -1)
-			err(1, "pledge");
-#endif
-	} else if (strcmp(proto, "http") == 0 ||
-	    strcmp(proto, "git+http") == 0) {
-		error = got_error_path(proto, GOT_ERR_NOT_IMPL);
-		goto done;
-	} else {
-		error = got_error_path(proto, GOT_ERR_BAD_PROTO);
-		goto done;
-	}
-
-	error = got_dial_apply_unveil(proto);
-	if (error)
-		goto done;
-
-	error = apply_unveil(got_repo_get_path(repo), 0, NULL);
-	if (error)
-		goto done;
-
-	if (send_all_branches) {
-		error = got_ref_list(&all_branches, repo, "refs/heads",
-		    got_ref_cmp_by_name, NULL);
-		if (error)
-			goto done;
-		TAILQ_FOREACH(re, &all_branches, entry) {
-			const char *branchname = got_ref_get_name(re->ref);
-			error = got_pathlist_append(&branches,
-			    branchname, NULL);
-			if (error)
-				goto done;
-			nbranches++;
-		}
-	} else if (nbranches == 0) {
-		for (i = 0; i < remote->nsend_branches; i++) {
-			error = got_pathlist_append(&branches,
-			    remote->send_branches[i], NULL);
-			if (error)
-				goto done;
-		}
-	}
-
-	if (send_all_tags) {
-		error = got_ref_list(&all_tags, repo, "refs/tags",
-		    got_ref_cmp_by_name, NULL);
-		if (error)
-			goto done;
-		TAILQ_FOREACH(re, &all_tags, entry) {
-			const char *tagname = got_ref_get_name(re->ref);
-			error = got_pathlist_append(&tags,
-			    tagname, NULL);
-			if (error)
-				goto done;
-		}
-	}
-
-	/*
-	 * To prevent accidents only branches in refs/heads/ can be deleted
-	 * with 'got send -d'.
-	 * Deleting anything else requires local repository access or Git.
-	 */
-	TAILQ_FOREACH(pe, &delete_args, entry) {
-		const char *branchname = pe->path;
-		char *s;
-		struct got_pathlist_entry *new;
-		if (strncmp(branchname, "refs/heads/", 11) == 0) {
-			s = strdup(branchname);
-			if (s == NULL) {
-				error = got_error_from_errno("strdup");
-				goto done;
-			}
-		} else {
-			if (asprintf(&s, "refs/heads/%s", branchname) == -1) {
-				error = got_error_from_errno("asprintf");
-				goto done;
-			}
-		}
-		error = got_pathlist_insert(&new, &delete_branches, s, NULL);
-		if (error || new == NULL /* duplicate */)
-			free(s);
-		if (error)
-			goto done;
-		ndelete_branches++;
-	}
-
-	if (nbranches == 0 && ndelete_branches == 0) {
-		struct got_reference *head_ref;
-		if (worktree)
-			error = got_ref_open(&head_ref, repo,
-			    got_worktree_get_head_ref_name(worktree), 0);
-		else
-			error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
-		if (error)
-			goto done;
-		if (got_ref_is_symbolic(head_ref)) {
-			error = got_ref_resolve_symbolic(&ref, repo, head_ref);
-			got_ref_close(head_ref);
-			if (error)
-				goto done;
-		} else
-			ref = head_ref;
-		error = got_pathlist_append(&branches, got_ref_get_name(ref),
-		    NULL);
-		if (error)
-			goto done;
-		nbranches++;
-	}
-
-	if (verbosity >= 0) {
-		printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
-		    remote->name, proto, host,
-		    port ? ":" : "", port ? port : "",
-		    *server_path == '/' ? "" : "/", server_path);
-	}
-
-	error = got_send_connect(&sendpid, &sendfd, proto, host, port,
-	    server_path, verbosity);
-	if (error)
-		goto done;
-
-	memset(&spa, 0, sizeof(spa));
-	spa.last_scaled_packsize[0] = '\0';
-	spa.last_p_deltify = -1;
-	spa.last_p_written = -1;
-	spa.verbosity = verbosity;
-	spa.delete_branches = &delete_branches;
-	error = got_send_pack(remote_name, &branches, &tags, &delete_branches,
-	    verbosity, overwrite_refs, sendfd, repo, send_progress, &spa,
-	    check_cancelled, NULL);
-	if (spa.printed_something)
-		putchar('\n');
-	if (error)
-		goto done;
-	if (!spa.sent_something && verbosity >= 0)
-		printf("Already up-to-date\n");
-done:
-	if (sendpid > 0) {
-		if (kill(sendpid, SIGTERM) == -1)
-			error = got_error_from_errno("kill");
-		if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL)
-			error = got_error_from_errno("waitpid");
-	}
-	if (sendfd != -1 && close(sendfd) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (worktree)
-		got_worktree_close(worktree);
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	if (ref)
-		got_ref_close(ref);
-	got_pathlist_free(&branches, GOT_PATHLIST_FREE_NONE);
-	got_pathlist_free(&tags, GOT_PATHLIST_FREE_NONE);
-	got_ref_list_free(&all_branches);
-	got_ref_list_free(&all_tags);
-	got_pathlist_free(&delete_args, GOT_PATHLIST_FREE_NONE);
-	got_pathlist_free(&delete_branches, GOT_PATHLIST_FREE_PATH);
-	free(cwd);
-	free(repo_path);
-	free(proto);
-	free(host);
-	free(port);
-	free(server_path);
-	free(repo_name);
-	return error;
-}
-
-/*
- * Print and if delete is set delete all ref_prefix references.
- * If wanted_ref is not NULL, only print or delete this reference.
- */
-static const struct got_error *
-process_logmsg_refs(const char *ref_prefix, size_t prefix_len,
-    const char *wanted_ref, int delete, struct got_worktree *worktree,
-    struct got_repository *repo)
-{
-	const struct got_error			*err;
-	struct got_pathlist_head		 paths;
-	struct got_reflist_head			 refs;
-	struct got_reflist_entry		*re;
-	struct got_reflist_object_id_map	*refs_idmap = NULL;
-	struct got_commit_object		*commit = NULL;
-	struct got_object_id			*id = NULL;
-	const char				*header_prefix;
-	char					*uuidstr = NULL;
-	int					 found = 0;
-
-	TAILQ_INIT(&refs);
-	TAILQ_INIT(&paths);
-
-	err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo);
-	if (err)
-		goto done;
-
-	err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
-	if (err)
-		goto done;
-
-	if (worktree != NULL) {
-		err = got_worktree_get_uuid(&uuidstr, worktree);
-		if (err)
-			goto done;
-	}
-
-	if (wanted_ref) {
-		if (strncmp(wanted_ref, "refs/heads/", 11) == 0)
-			wanted_ref += 11;
-	}
-
-	if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0)
-		header_prefix = "backout";
-	else
-		header_prefix = "cherrypick";
-
-	TAILQ_FOREACH(re, &refs, entry) {
-		const char *refname, *wt;
-
-		refname = got_ref_get_name(re->ref);
-
-		err = check_cancelled(NULL);
-		if (err)
-			goto done;
-
-		if (strncmp(refname, ref_prefix, prefix_len) == 0)
-			refname += prefix_len + 1;  /* skip '-' delimiter */
-		else
-			continue;
-
-		wt = refname;
-
-		if (worktree == NULL || strncmp(refname, uuidstr,
-		    GOT_WORKTREE_UUID_STRLEN) == 0)
-			refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
-		else
-			continue;
-
-		err = got_repo_match_object_id(&id, NULL, refname,
-		    GOT_OBJ_TYPE_COMMIT, NULL, repo);
-		if (err)
-			goto done;
-
-		err = got_object_open_as_commit(&commit, repo, id);
-		if (err)
-			goto done;
-
-		if (wanted_ref)
-			found = strncmp(wanted_ref, refname,
-			    strlen(wanted_ref)) == 0;
-		if (wanted_ref && !found) {
-			struct got_reflist_head	*ci_refs;
-
-			ci_refs = got_reflist_object_id_map_lookup(refs_idmap,
-			    id);
-
-			if (ci_refs) {
-				char		*refs_str = NULL;
-				char const	*r = NULL;
-
-				err = build_refs_str(&refs_str, ci_refs, id,
-				    repo, 1);
-				if (err)
-					goto done;
-
-				r = refs_str;
-				while (r) {
-					if (strncmp(r, wanted_ref,
-					    strlen(wanted_ref)) == 0) {
-						found = 1;
-						break;
-					}
-					r = strchr(r, ' ');
-					if (r)
-						++r;
-				}
-				free(refs_str);
-			}
-		}
-
-		if (wanted_ref == NULL || found) {
-			if (delete) {
-				err = got_ref_delete(re->ref, repo);
-				if (err)
-					goto done;
-				printf("Deleted: ");
-				err = print_commit_oneline(commit, id, repo,
-				    refs_idmap);
-			} else {
-				/*
-				 * Print paths modified by commit to help
-				 * associate commits with worktree changes.
-				 */
-				err = get_changed_paths(&paths, commit,
-				    repo, NULL);
-				if (err)
-					goto done;
-
-				err = print_commit(commit, id, repo, NULL,
-				    &paths, NULL, 0, 0, refs_idmap, NULL,
-				    header_prefix);
-				got_pathlist_free(&paths,
-				    GOT_PATHLIST_FREE_ALL);
-
-				if (worktree == NULL)
-					printf("work tree: %.*s\n\n",
-					    GOT_WORKTREE_UUID_STRLEN, wt);
-			}
-			if (err || found)
-				goto done;
-		}
-
-		got_object_commit_close(commit);
-		commit = NULL;
-		free(id);
-		id = NULL;
-	}
-
-	if (wanted_ref != NULL && !found)
-		err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref);
-
-done:
-	free(id);
-	free(uuidstr);
-	got_ref_list_free(&refs);
-	got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
-	if (refs_idmap)
-		got_reflist_object_id_map_free(refs_idmap);
-	if (commit)
-		got_object_commit_close(commit);
-	return err;
-}
-
-/*
- * Create new temp "logmsg" ref of the backed-out or cherrypicked commit
- * identified by id for log messages to prepopulate the editor on commit.
- */
-static const struct got_error *
-logmsg_ref(struct got_object_id *id, const char *prefix,
-    struct got_worktree *worktree, struct got_repository *repo)
-{
-	const struct got_error	*err = NULL;
-	char			*idstr, *ref = NULL, *refname = NULL;
-	int			 histedit_in_progress;
-	int			 rebase_in_progress, merge_in_progress;
-
-	/*
-	 * Silenty refuse to create merge reference if any histedit, merge,
-	 * or rebase operation is in progress.
-	 */
-	err = got_worktree_histedit_in_progress(&histedit_in_progress,
-	    worktree);
-	if (err)
-		return err;
-	if (histedit_in_progress)
-		return NULL;
-
-	err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
-	if (err)
-		return err;
-	if (rebase_in_progress)
-		return NULL;
-
-	err = got_worktree_merge_in_progress(&merge_in_progress, worktree,
-	    repo);
-	if (err)
-		return err;
-	if (merge_in_progress)
-		return NULL;
-
-	err = got_object_id_str(&idstr, id);
-	if (err)
-		return err;
-
-	err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix);
-	if (err)
-		goto done;
-
-	if (asprintf(&ref, "%s-%s", refname, idstr) == -1) {
-		err = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	err = create_ref(ref, got_worktree_get_base_commit_id(worktree),
-	    -1, repo);
-done:
-	free(ref);
-	free(idstr);
-	free(refname);
-	return err;
-}
-
-__dead static void
-usage_cherrypick(void)
-{
-	fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
-	    getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-cmd_cherrypick(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_worktree *worktree = NULL;
-	struct got_repository *repo = NULL;
-	char *cwd = NULL, *commit_id_str = NULL;
-	struct got_object_id *commit_id = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_object_qid *pid;
-	int ch, list_refs = 0, remove_refs = 0;
-	struct got_update_progress_arg upa;
-	int *pack_fds = NULL;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "lX")) != -1) {
-		switch (ch) {
-		case 'l':
-			list_refs = 1;
-			break;
-		case 'X':
-			remove_refs = 1;
-			break;
-		default:
-			usage_cherrypick();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (list_refs || remove_refs) {
-		if (argc != 0 && argc != 1)
-			usage_cherrypick();
-	} else if (argc != 1)
-		usage_cherrypick();
-	if (list_refs && remove_refs)
-		option_conflict('l', 'X');
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (list_refs || remove_refs) {
-			if (error->code != GOT_ERR_NOT_WORKTREE)
-				goto done;
-		} else {
-			if (error->code == GOT_ERR_NOT_WORKTREE)
-				error = wrap_not_worktree_error(error,
-				    "cherrypick", cwd);
-			goto done;
-		}
-	}
-
-	error = got_repo_open(&repo,
-	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
-	    NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    worktree ? got_worktree_get_root_path(worktree) : NULL);
-	if (error)
-		goto done;
-
-	if (list_refs || remove_refs) {
-		error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
-		    GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN,
-		    argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
-		goto done;
-	}
-
-	error = got_repo_match_object_id(&commit_id, NULL, argv[0],
-	    GOT_OBJ_TYPE_COMMIT, NULL, repo);
-	if (error)
-		goto done;
-	error = got_object_id_str(&commit_id_str, commit_id);
-	if (error)
-		goto done;
-
-	error = got_object_open_as_commit(&commit, repo, commit_id);
-	if (error)
-		goto done;
-	pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
-	memset(&upa, 0, sizeof(upa));
-	error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL,
-	    commit_id, repo, update_progress, &upa, check_cancelled,
-	    NULL);
-	if (error != NULL)
-		goto done;
-
-	if (upa.did_something) {
-		error = logmsg_ref(commit_id,
-		    GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo);
-		if (error)
-			goto done;
-		printf("Merged commit %s\n", commit_id_str);
-	}
-	print_merge_progress_stats(&upa);
-done:
-	free(cwd);
-	if (commit)
-		got_object_commit_close(commit);
-	free(commit_id_str);
-	if (worktree)
-		got_worktree_close(worktree);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-
-	return error;
-}
-
-__dead static void
-usage_backout(void)
-{
-	fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-cmd_backout(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_worktree *worktree = NULL;
-	struct got_repository *repo = NULL;
-	char *cwd = NULL, *commit_id_str = NULL;
-	struct got_object_id *commit_id = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_object_qid *pid;
-	int ch, list_refs = 0, remove_refs = 0;
-	struct got_update_progress_arg upa;
-	int *pack_fds = NULL;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "lX")) != -1) {
-		switch (ch) {
-		case 'l':
-			list_refs = 1;
-			break;
-		case 'X':
-			remove_refs = 1;
-			break;
-		default:
-			usage_backout();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (list_refs || remove_refs) {
-		if (argc != 0 && argc != 1)
-			usage_backout();
-	} else if (argc != 1)
-		usage_backout();
-	if (list_refs && remove_refs)
-		option_conflict('l', 'X');
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (list_refs || remove_refs) {
-			if (error->code != GOT_ERR_NOT_WORKTREE)
-				goto done;
-		} else {
-			if (error->code == GOT_ERR_NOT_WORKTREE)
-				error = wrap_not_worktree_error(error,
-				    "backout", cwd);
-			goto done;
-		}
-	}
-
-	error = got_repo_open(&repo,
-	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
-	    NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    worktree ? got_worktree_get_root_path(worktree) : NULL);
-	if (error)
-		goto done;
-
-	if (list_refs || remove_refs) {
-		error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX,
-		    GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN,
-		    argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
-		goto done;
-	}
-
-	error = got_repo_match_object_id(&commit_id, NULL, argv[0],
-	    GOT_OBJ_TYPE_COMMIT, NULL, repo);
-	if (error)
-		goto done;
-	error = got_object_id_str(&commit_id_str, commit_id);
-	if (error)
-		goto done;
-
-	error = got_object_open_as_commit(&commit, repo, commit_id);
-	if (error)
-		goto done;
-	pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
-	if (pid == NULL) {
-		error = got_error(GOT_ERR_ROOT_COMMIT);
-		goto done;
-	}
-
-	memset(&upa, 0, sizeof(upa));
-	error = got_worktree_merge_files(worktree, commit_id, &pid->id,
-	    repo, update_progress, &upa, check_cancelled, NULL);
-	if (error != NULL)
-		goto done;
-
-	if (upa.did_something) {
-		error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX,
-		    worktree, repo);
-		if (error)
-			goto done;
-		printf("Backed out commit %s\n", commit_id_str);
-	}
-	print_merge_progress_stats(&upa);
-done:
-	free(cwd);
-	if (commit)
-		got_object_commit_close(commit);
-	free(commit_id_str);
-	if (worktree)
-		got_worktree_close(worktree);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	return error;
-}
-
-__dead static void
-usage_rebase(void)
-{
-	fprintf(stderr, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
-	exit(1);
-}
-
-static void
-trim_logmsg(char *logmsg, int limit)
-{
-	char *nl;
-	size_t len;
-
-	len = strlen(logmsg);
-	if (len > limit)
-		len = limit;
-	logmsg[len] = '\0';
-	nl = strchr(logmsg, '\n');
-	if (nl)
-		*nl = '\0';
-}
-
-static const struct got_error *
-get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
-{
-	const struct got_error *err;
-	char *logmsg0 = NULL;
-	const char *s;
-
-	err = got_object_commit_get_logmsg(&logmsg0, commit);
-	if (err)
-		return err;
-
-	s = logmsg0;
-	while (isspace((unsigned char)s[0]))
-		s++;
-
-	*logmsg = strdup(s);
-	if (*logmsg == NULL) {
-		err = got_error_from_errno("strdup");
-		goto done;
-	}
-
-	trim_logmsg(*logmsg, limit);
-done:
-	free(logmsg0);
-	return err;
-}
-
-static const struct got_error *
-show_rebase_merge_conflict(struct got_object_id *id,
-    struct got_repository *repo)
-{
-	const struct got_error *err;
-	struct got_commit_object *commit = NULL;
-	char *id_str = NULL, *logmsg = NULL;
-
-	err = got_object_open_as_commit(&commit, repo, id);
-	if (err)
-		return err;
-
-	err = got_object_id_str(&id_str, id);
-	if (err)
-		goto done;
-
-	id_str[12] = '\0';
-
-	err = get_short_logmsg(&logmsg, 42, commit);
-	if (err)
-		goto done;
-
-	printf("%s -> merge conflict: %s\n", id_str, logmsg);
-done:
-	free(id_str);
-	got_object_commit_close(commit);
-	free(logmsg);
-	return err;
-}
-
-static const struct got_error *
-show_rebase_progress(struct got_commit_object *commit,
-    struct got_object_id *old_id, struct got_object_id *new_id)
-{
-	const struct got_error *err;
-	char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
-
-	err = got_object_id_str(&old_id_str, old_id);
-	if (err)
-		goto done;
-
-	if (new_id) {
-		err = got_object_id_str(&new_id_str, new_id);
-		if (err)
-			goto done;
-	}
-
-	old_id_str[12] = '\0';
-	if (new_id_str)
-		new_id_str[12] = '\0';
-
-	err = get_short_logmsg(&logmsg, 42, commit);
-	if (err)
-		goto done;
-
-	printf("%s -> %s: %s\n", old_id_str,
-	    new_id_str ? new_id_str : "no-op change", logmsg);
-done:
-	free(old_id_str);
-	free(new_id_str);
-	free(logmsg);
-	return err;
-}
-
-static const struct got_error *
-rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
-    struct got_reference *branch, struct got_reference *tmp_branch,
-    struct got_repository *repo, int create_backup)
-{
-	printf("Switching work tree to %s\n", got_ref_get_name(branch));
-	return got_worktree_rebase_complete(worktree, fileindex,
-	    tmp_branch, branch, repo, create_backup);
-}
-
-static const struct got_error *
-rebase_commit(struct got_pathlist_head *merged_paths,
-    struct got_worktree *worktree, struct got_fileindex *fileindex,
-    struct got_reference *tmp_branch, const char *committer,
-    struct got_object_id *commit_id, int allow_conflict,
-    struct got_repository *repo)
-{
-	const struct got_error *error;
-	struct got_commit_object *commit;
-	struct got_object_id *new_commit_id;
-
-	error = got_object_open_as_commit(&commit, repo, commit_id);
-	if (error)
-		return error;
-
-	error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
-	    worktree, fileindex, tmp_branch, committer, commit, commit_id,
-	    allow_conflict, repo);
-	if (error) {
-		if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
-			goto done;
-		error = show_rebase_progress(commit, commit_id, NULL);
-	} else {
-		error = show_rebase_progress(commit, commit_id, new_commit_id);
-		free(new_commit_id);
-	}
-done:
-	got_object_commit_close(commit);
-	return error;
-}
-
-struct check_path_prefix_arg {
-	const char *path_prefix;
-	size_t len;
-	int errcode;
-};
-
-static const struct got_error *
-check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
-    struct got_blob_object *blob2, FILE *f1, FILE *f2,
-    struct got_object_id *id1, struct got_object_id *id2,
-    const char *path1, const char *path2,
-    mode_t mode1, mode_t mode2, struct got_repository *repo)
-{
-	struct check_path_prefix_arg *a = arg;
-
-	if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
-	    (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
-		return got_error(a->errcode);
-
-	return NULL;
-}
-
-static const struct got_error *
-check_path_prefix(struct got_object_id *parent_id,
-    struct got_object_id *commit_id, const char *path_prefix,
-    int errcode, struct got_repository *repo)
-{
-	const struct got_error *err;
-	struct got_tree_object *tree1 = NULL, *tree2 = NULL;
-	struct got_commit_object *commit = NULL, *parent_commit = NULL;
-	struct check_path_prefix_arg cpp_arg;
-
-	if (got_path_is_root_dir(path_prefix))
-		return NULL;
-
-	err = got_object_open_as_commit(&commit, repo, commit_id);
-	if (err)
-		goto done;
-
-	err = got_object_open_as_commit(&parent_commit, repo, parent_id);
-	if (err)
-		goto done;
-
-	err = got_object_open_as_tree(&tree1, repo,
-	    got_object_commit_get_tree_id(parent_commit));
-	if (err)
-		goto done;
-
-	err = got_object_open_as_tree(&tree2, repo,
-	    got_object_commit_get_tree_id(commit));
-	if (err)
-		goto done;
-
-	cpp_arg.path_prefix = path_prefix;
-	while (cpp_arg.path_prefix[0] == '/')
-		cpp_arg.path_prefix++;
-	cpp_arg.len = strlen(cpp_arg.path_prefix);
-	cpp_arg.errcode = errcode;
-	err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo,
-	    check_path_prefix_in_diff, &cpp_arg, 0);
-done:
-	if (tree1)
-		got_object_tree_close(tree1);
-	if (tree2)
-		got_object_tree_close(tree2);
-	if (commit)
-		got_object_commit_close(commit);
-	if (parent_commit)
-		got_object_commit_close(parent_commit);
-	return err;
-}
-
-static const struct got_error *
-collect_commits(struct got_object_id_queue *commits,
-    struct got_object_id *initial_commit_id,
-    struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
-    const char *path_prefix, int path_prefix_errcode,
-    struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_commit_graph *graph = NULL;
-	struct got_object_id parent_id, commit_id;
-	struct got_object_qid *qid;
-
-	err = got_commit_graph_open(&graph, "/", 1);
-	if (err)
-		return err;
-
-	err = got_commit_graph_iter_start(graph, iter_start_id, repo,
-	    check_cancelled, NULL);
-	if (err)
-		goto done;
-
-	memcpy(&commit_id, initial_commit_id, sizeof(commit_id));
-	while (got_object_id_cmp(&commit_id, iter_stop_id) != 0) {
-		err = got_commit_graph_iter_next(&parent_id, graph, repo,
-		    check_cancelled, NULL);
-		if (err) {
-			if (err->code == GOT_ERR_ITER_COMPLETED) {
-				err = got_error_msg(GOT_ERR_ANCESTRY,
-				    "ran out of commits to rebase before "
-				    "youngest common ancestor commit has "
-				    "been reached?!?");
-			}
-			goto done;
-		} else {
-			err = check_path_prefix(&parent_id, &commit_id,
-			    path_prefix, path_prefix_errcode, repo);
-			if (err)
-				goto done;
-
-			err = got_object_qid_alloc(&qid, &commit_id);
-			if (err)
-				goto done;
-			STAILQ_INSERT_HEAD(commits, qid, entry);
-
-			memcpy(&commit_id, &parent_id, sizeof(commit_id));
-		}
-	}
-done:
-	got_commit_graph_close(graph);
-	return err;
-}
-
-static const struct got_error *
-get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
-{
-	const struct got_error *err = NULL;
-	time_t committer_time;
-	struct tm tm;
-	char datebuf[11]; /* YYYY-MM-DD + NUL */
-	char *author0 = NULL, *author, *smallerthan;
-	char *logmsg0 = NULL, *logmsg, *newline;
-
-	committer_time = got_object_commit_get_committer_time(commit);
-	if (gmtime_r(&committer_time, &tm) == NULL)
-		return got_error_from_errno("gmtime_r");
-	if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
-		return got_error(GOT_ERR_NO_SPACE);
-
-	author0 = strdup(got_object_commit_get_author(commit));
-	if (author0 == NULL)
-		return got_error_from_errno("strdup");
-	author = author0;
-	smallerthan = strchr(author, '<');
-	if (smallerthan && smallerthan[1] != '\0')
-		author = smallerthan + 1;
-	author[strcspn(author, "@>")] = '\0';
-
-	err = got_object_commit_get_logmsg(&logmsg0, commit);
-	if (err)
-		goto done;
-	logmsg = logmsg0;
-	while (*logmsg == '\n')
-		logmsg++;
-	newline = strchr(logmsg, '\n');
-	if (newline)
-		*newline = '\0';
-
-	if (asprintf(brief_str, "%s %s  %s",
-	    datebuf, author, logmsg) == -1)
-		err = got_error_from_errno("asprintf");
-done:
-	free(author0);
-	free(logmsg0);
-	return err;
-}
-
-static const struct got_error *
-delete_backup_ref(struct got_reference *ref, struct got_object_id *id,
-    struct got_repository *repo)
-{
-	const struct got_error *err;
-	char *id_str;
-
-	err = got_object_id_str(&id_str, id);
-	if (err)
-		return err;
-
-	err = got_ref_delete(ref, repo);
-	if (err)
-		goto done;
-
-	printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str);
-done:
-	free(id_str);
-	return err;
-}
-
-static const struct got_error *
-print_backup_ref(const char *branch_name, const char *new_id_str,
-    struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
-    struct got_reflist_object_id_map *refs_idmap,
-    struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_reflist_head *refs;
-	char *refs_str = NULL;
-	struct got_object_id *new_commit_id = NULL;
-	struct got_commit_object *new_commit = NULL;
-	char *new_commit_brief_str = NULL;
-	struct got_object_id *yca_id = NULL;
-	struct got_commit_object *yca_commit = NULL;
-	char *yca_id_str = NULL, *yca_brief_str = NULL;
-	char *custom_refs_str;
-
-	if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
-		return got_error_from_errno("asprintf");
-
-	err = print_commit(old_commit, old_commit_id, repo, NULL, NULL, NULL,
-	    0, 0, refs_idmap, custom_refs_str, NULL);
-	if (err)
-		goto done;
-
-	err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
-	if (err)
-		goto done;
-
-	refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
-	if (refs) {
-		err = build_refs_str(&refs_str, refs, new_commit_id, repo, 0);
-		if (err)
-			goto done;
-	}
-
-	err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
-	if (err)
-		goto done;
-
-	err = get_commit_brief_str(&new_commit_brief_str, new_commit);
-	if (err)
-		goto done;
-
-	err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
-	    old_commit_id, new_commit_id, 1, repo, check_cancelled, NULL);
-	if (err)
-		goto done;
-
-	printf("has become commit %s%s%s%s\n %s\n", new_id_str,
-	    refs_str ? " (" : "", refs_str ? refs_str : "",
-	    refs_str ? ")" : "", new_commit_brief_str);
-	if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
-	    got_object_id_cmp(yca_id, old_commit_id) != 0) {
-		free(refs_str);
-		refs_str = NULL;
-
-		err = got_object_open_as_commit(&yca_commit, repo, yca_id);
-		if (err)
-			goto done;
-
-		err = get_commit_brief_str(&yca_brief_str, yca_commit);
-		if (err)
-			goto done;
-
-		err = got_object_id_str(&yca_id_str, yca_id);
-		if (err)
-			goto done;
-
-		refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
-		if (refs) {
-			err = build_refs_str(&refs_str, refs, yca_id, repo, 0);
-			if (err)
-				goto done;
-		}
-		printf("history forked at %s%s%s%s\n %s\n",
-		    yca_id_str,
-		    refs_str ? " (" : "", refs_str ? refs_str : "",
-		    refs_str ? ")" : "", yca_brief_str);
-	}
-done:
-	free(custom_refs_str);
-	free(new_commit_id);
-	free(refs_str);
-	free(yca_id);
-	free(yca_id_str);
-	free(yca_brief_str);
-	if (new_commit)
-		got_object_commit_close(new_commit);
-	if (yca_commit)
-		got_object_commit_close(yca_commit);
-
-	return err;
-}
-
-static const struct got_error *
-worktree_has_logmsg_ref(const char *caller, struct got_worktree *worktree,
-    struct got_repository *repo)
-{
-	const struct got_error		*err;
-	struct got_reflist_head		 refs;
-	struct got_reflist_entry	*re;
-	char				*uuidstr = NULL;
-	static char			 msg[160];
-
-	TAILQ_INIT(&refs);
-
-	err = got_worktree_get_uuid(&uuidstr, worktree);
-	if (err)
-		goto done;
-
-	err = got_ref_list(&refs, repo, "refs/got/worktree",
-	    got_ref_cmp_by_name, repo);
-	if (err)
-		goto done;
-
-	TAILQ_FOREACH(re, &refs, entry) {
-		const char *cmd, *refname, *type;
-
-		refname = got_ref_get_name(re->ref);
-
-		if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
-		    GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) {
-			refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
-			cmd = "cherrypick";
-			type = "cherrypicked";
-		} else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
-		    GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) {
-			refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
-			cmd = "backout";
-			type = "backed-out";
-		} else
-			continue;
-
-		if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) != 0)
-			continue;
-
-		snprintf(msg, sizeof(msg),
-		    "work tree has references created by %s commits which "
-		    "must be removed with 'got %s -X' before running the %s "
-		    "command", type, cmd, caller);
-		err = got_error_msg(GOT_ERR_WORKTREE_META, msg);
-		goto done;
-	}
-
-done:
-	free(uuidstr);
-	got_ref_list_free(&refs);
-	return err;
-}
-
-static const struct got_error *
-process_backup_refs(const char *backup_ref_prefix,
-    const char *wanted_branch_name,
-    int delete, struct got_repository *repo)
-{
-	const struct got_error *err;
-	struct got_reflist_head refs, backup_refs;
-	struct got_reflist_entry *re;
-	const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
-	struct got_object_id *old_commit_id = NULL;
-	char *branch_name = NULL;
-	struct got_commit_object *old_commit = NULL;
-	struct got_reflist_object_id_map *refs_idmap = NULL;
-	int wanted_branch_found = 0;
-
-	TAILQ_INIT(&refs);
-	TAILQ_INIT(&backup_refs);
-
-	err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
-	if (err)
-		return err;
-
-	err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
-	if (err)
-		goto done;
-
-	if (wanted_branch_name) {
-		if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
-			wanted_branch_name += 11;
-	}
-
-	err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
-	    got_ref_cmp_by_commit_timestamp_descending, repo);
-	if (err)
-		goto done;
-
-	TAILQ_FOREACH(re, &backup_refs, entry) {
-		const char *refname = got_ref_get_name(re->ref);
-		char *slash;
-
-		err = check_cancelled(NULL);
-		if (err)
-			break;
-
-		err = got_ref_resolve(&old_commit_id, repo, re->ref);
-		if (err)
-			break;
-
-		err = got_object_open_as_commit(&old_commit, repo,
-		    old_commit_id);
-		if (err)
-			break;
-
-		if (strncmp(backup_ref_prefix, refname,
-		    backup_ref_prefix_len) == 0)
-			refname += backup_ref_prefix_len;
-
-		while (refname[0] == '/')
-			refname++;
-
-		branch_name = strdup(refname);
-		if (branch_name == NULL) {
-			err = got_error_from_errno("strdup");
-			break;
-		}
-		slash = strrchr(branch_name, '/');
-		if (slash) {
-			*slash = '\0';
-			refname += strlen(branch_name) + 1;
-		}
-
-		if (wanted_branch_name == NULL ||
-		    strcmp(wanted_branch_name, branch_name) == 0) {
-			wanted_branch_found = 1;
-			if (delete) {
-				err = delete_backup_ref(re->ref,
-				    old_commit_id, repo);
-			} else {
-				err = print_backup_ref(branch_name, refname,
-				    old_commit_id, old_commit, refs_idmap,
-				    repo);
-			}
-			if (err)
-				break;
-		}
-
-		free(old_commit_id);
-		old_commit_id = NULL;
-		free(branch_name);
-		branch_name = NULL;
-		got_object_commit_close(old_commit);
-		old_commit = NULL;
-	}
-
-	if (wanted_branch_name && !wanted_branch_found) {
-		err = got_error_fmt(GOT_ERR_NOT_REF,
-		    "%s/%s/", backup_ref_prefix, wanted_branch_name);
-	}
-done:
-	if (refs_idmap)
-		got_reflist_object_id_map_free(refs_idmap);
-	got_ref_list_free(&refs);
-	got_ref_list_free(&backup_refs);
-	free(old_commit_id);
-	free(branch_name);
-	if (old_commit)
-		got_object_commit_close(old_commit);
-	return err;
-}
-
-static const struct got_error *
-abort_progress(void *arg, unsigned char status, const char *path)
-{
-	/*
-	 * Unversioned files should not clutter progress output when
-	 * an operation is aborted.
-	 */
-	if (status == GOT_STATUS_UNVERSIONED)
-		return NULL;
-
-	return update_progress(arg, status, path);
-}
-
-static const struct got_error *
-cmd_rebase(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_worktree *worktree = NULL;
-	struct got_repository *repo = NULL;
-	struct got_fileindex *fileindex = NULL;
-	char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
-	struct got_reference *branch = NULL;
-	struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
-	struct got_object_id *commit_id = NULL, *parent_id = NULL;
-	struct got_object_id *resume_commit_id = NULL;
-	struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
-	struct got_object_id *head_commit_id = NULL;
-	struct got_reference *head_ref = NULL;
-	struct got_commit_object *commit = NULL;
-	int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
-	int histedit_in_progress = 0, merge_in_progress = 0;
-	int create_backup = 1, list_backups = 0, delete_backups = 0;
-	int allow_conflict = 0;
-	struct got_object_id_queue commits;
-	struct got_pathlist_head merged_paths;
-	const struct got_object_id_queue *parent_ids;
-	struct got_object_qid *qid, *pid;
-	struct got_update_progress_arg upa;
-	int *pack_fds = NULL;
-
-	STAILQ_INIT(&commits);
-	TAILQ_INIT(&merged_paths);
-	memset(&upa, 0, sizeof(upa));
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "aCclX")) != -1) {
-		switch (ch) {
-		case 'a':
-			abort_rebase = 1;
-			break;
-		case 'C':
-			allow_conflict = 1;
-			break;
-		case 'c':
-			continue_rebase = 1;
-			break;
-		case 'l':
-			list_backups = 1;
-			break;
-		case 'X':
-			delete_backups = 1;
-			break;
-		default:
-			usage_rebase();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (list_backups) {
-		if (abort_rebase)
-			option_conflict('l', 'a');
-		if (allow_conflict)
-			option_conflict('l', 'C');
-		if (continue_rebase)
-			option_conflict('l', 'c');
-		if (delete_backups)
-			option_conflict('l', 'X');
-		if (argc != 0 && argc != 1)
-			usage_rebase();
-	} else if (delete_backups) {
-		if (abort_rebase)
-			option_conflict('X', 'a');
-		if (allow_conflict)
-			option_conflict('X', 'C');
-		if (continue_rebase)
-			option_conflict('X', 'c');
-		if (list_backups)
-			option_conflict('l', 'X');
-		if (argc != 0 && argc != 1)
-			usage_rebase();
-	} else if (allow_conflict) {
-		if (abort_rebase)
-			option_conflict('C', 'a');
-		if (!continue_rebase)
-			errx(1, "-C option requires -c");
-	} else {
-		if (abort_rebase && continue_rebase)
-			usage_rebase();
-		else if (abort_rebase || continue_rebase) {
-			if (argc != 0)
-				usage_rebase();
-		} else if (argc != 1)
-			usage_rebase();
-	}
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (list_backups || delete_backups) {
-			if (error->code != GOT_ERR_NOT_WORKTREE)
-				goto done;
-		} else {
-			if (error->code == GOT_ERR_NOT_WORKTREE)
-				error = wrap_not_worktree_error(error,
-				    "rebase", cwd);
-			goto done;
-		}
-	}
-
-	error = get_gitconfig_path(&gitconfig_path);
-	if (error)
-		goto done;
-	error = got_repo_open(&repo,
-	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
-	    gitconfig_path, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (worktree != NULL && !list_backups && !delete_backups) {
-		error = worktree_has_logmsg_ref("rebase", worktree, repo);
-		if (error)
-			goto done;
-	}
-
-	error = get_author(&committer, repo, worktree);
-	if (error && error->code != GOT_ERR_COMMIT_NO_AUTHOR)
-		goto done;
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    worktree ? got_worktree_get_root_path(worktree) : NULL);
-	if (error)
-		goto done;
-
-	if (list_backups || delete_backups) {
-		error = process_backup_refs(
-		    GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
-		    argc == 1 ? argv[0] : NULL, delete_backups, repo);
-		goto done; /* nothing else to do */
-	}
-
-	error = got_worktree_histedit_in_progress(&histedit_in_progress,
-	    worktree);
-	if (error)
-		goto done;
-	if (histedit_in_progress) {
-		error = got_error(GOT_ERR_HISTEDIT_BUSY);
-		goto done;
-	}
-
-	error = got_worktree_merge_in_progress(&merge_in_progress,
-	    worktree, repo);
-	if (error)
-		goto done;
-	if (merge_in_progress) {
-		error = got_error(GOT_ERR_MERGE_BUSY);
-		goto done;
-	}
-
-	error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
-	if (error)
-		goto done;
-
-	if (abort_rebase) {
-		if (!rebase_in_progress) {
-			error = got_error(GOT_ERR_NOT_REBASING);
-			goto done;
-		}
-		error = got_worktree_rebase_continue(&resume_commit_id,
-		    &new_base_branch, &tmp_branch, &branch, &fileindex,
-		    worktree, repo);
-		if (error)
-			goto done;
-		printf("Switching work tree to %s\n",
-		    got_ref_get_symref_target(new_base_branch));
-		error = got_worktree_rebase_abort(worktree, fileindex, repo,
-		    new_base_branch, abort_progress, &upa);
-		if (error)
-			goto done;
-		printf("Rebase of %s aborted\n", got_ref_get_name(branch));
-		print_merge_progress_stats(&upa);
-		goto done; /* nothing else to do */
-	}
-
-	if (continue_rebase) {
-		if (!rebase_in_progress) {
-			error = got_error(GOT_ERR_NOT_REBASING);
-			goto done;
-		}
-		error = got_worktree_rebase_continue(&resume_commit_id,
-		    &new_base_branch, &tmp_branch, &branch, &fileindex,
-		    worktree, repo);
-		if (error)
-			goto done;
-
-		error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
-		    committer, resume_commit_id, allow_conflict, repo);
-		if (error)
-			goto done;
-
-		yca_id = got_object_id_dup(resume_commit_id);
-		if (yca_id == NULL) {
-			error = got_error_from_errno("got_object_id_dup");
-			goto done;
-		}
-	} else {
-		error = got_ref_open(&branch, repo, argv[0], 0);
-		if (error != NULL)
-			goto done;
-		if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
-			error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
-			    "will not rebase a branch which lives outside "
-			    "the \"refs/heads/\" reference namespace");
-			goto done;
-		}
-	}
-
-	error = got_ref_resolve(&branch_head_commit_id, repo, branch);
-	if (error)
-		goto done;
-
-	if (!continue_rebase) {
-		struct got_object_id *base_commit_id;
-
-		error = got_ref_open(&head_ref, repo,
-		    got_worktree_get_head_ref_name(worktree), 0);
-		if (error)
-			goto done;
-		error = got_ref_resolve(&head_commit_id, repo, head_ref);
-		if (error)
-			goto done;
-		base_commit_id = got_worktree_get_base_commit_id(worktree);
-		if (got_object_id_cmp(base_commit_id, head_commit_id) != 0) {
-			error = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
-			goto done;
-		}
-
-		error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
-		    base_commit_id, branch_head_commit_id, 1, repo,
-		    check_cancelled, NULL);
-		if (error) {
-			if (error->code == GOT_ERR_ANCESTRY) {
-				error = got_error_msg(GOT_ERR_ANCESTRY,
-				    "specified branch shares no common "
-				    "ancestry with work tree's branch");
-			}
-			goto done;
-		}
-
-		if (got_object_id_cmp(base_commit_id, yca_id) == 0) {
-			struct got_pathlist_head paths;
-			printf("%s is already based on %s\n",
-			    got_ref_get_name(branch),
-			    got_worktree_get_head_ref_name(worktree));
-			error = switch_head_ref(branch, branch_head_commit_id,
-			    worktree, repo);
-			if (error)
-				goto done;
-			error = got_worktree_set_base_commit_id(worktree, repo,
-			    branch_head_commit_id);
-			if (error)
-				goto done;
-			TAILQ_INIT(&paths);
-			error = got_pathlist_append(&paths, "", NULL);
-			if (error)
-				goto done;
-			error = got_worktree_checkout_files(worktree,
-			    &paths, repo, update_progress, &upa,
-			    check_cancelled, NULL);
-			got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
-			if (error)
-				goto done;
-			if (upa.did_something) {
-				char *id_str;
-				error = got_object_id_str(&id_str,
-				    branch_head_commit_id);
-				if (error)
-					goto done;
-				printf("Updated to %s: %s\n",
-				    got_worktree_get_head_ref_name(worktree),
-				    id_str);
-				free(id_str);
-			} else
-				printf("Already up-to-date\n");
-			print_update_progress_stats(&upa);
-			goto done;
-		}
-	}
-
-	commit_id = branch_head_commit_id;
-	error = got_object_open_as_commit(&commit, repo, commit_id);
-	if (error)
-		goto done;
-
-	parent_ids = got_object_commit_get_parent_ids(commit);
-	pid = STAILQ_FIRST(parent_ids);
-	if (pid) {
-		error = collect_commits(&commits, commit_id, &pid->id,
-		    yca_id, got_worktree_get_path_prefix(worktree),
-		    GOT_ERR_REBASE_PATH, repo);
-		if (error)
-			goto done;
-	}
-
-	got_object_commit_close(commit);
-	commit = NULL;
-
-	if (!continue_rebase) {
-		error = got_worktree_rebase_prepare(&new_base_branch,
-		    &tmp_branch, &fileindex, worktree, branch, repo);
-		if (error)
-			goto done;
-	}
-
-	if (STAILQ_EMPTY(&commits)) {
-		if (continue_rebase) {
-			error = rebase_complete(worktree, fileindex,
-			    branch, tmp_branch, repo, create_backup);
-			goto done;
-		} else {
-			/* Fast-forward the reference of the branch. */
-			struct got_object_id *new_head_commit_id;
-			char *id_str;
-			error = got_ref_resolve(&new_head_commit_id, repo,
-			    new_base_branch);
-			if (error)
-				goto done;
-			error = got_object_id_str(&id_str, new_head_commit_id);
-			if (error)
-				goto done;
-			printf("Forwarding %s to commit %s\n",
-			    got_ref_get_name(branch), id_str);
-			free(id_str);
-			error = got_ref_change_ref(branch,
-			    new_head_commit_id);
-			if (error)
-				goto done;
-			/* No backup needed since objects did not change. */
-			create_backup = 0;
-		}
-	}
-
-	pid = NULL;
-	STAILQ_FOREACH(qid, &commits, entry) {
-
-		commit_id = &qid->id;
-		parent_id = pid ? &pid->id : yca_id;
-		pid = qid;
-
-		memset(&upa, 0, sizeof(upa));
-		error = got_worktree_rebase_merge_files(&merged_paths,
-		    worktree, fileindex, parent_id, commit_id, repo,
-		    update_progress, &upa, check_cancelled, NULL);
-		if (error)
-			goto done;
-
-		print_merge_progress_stats(&upa);
-		if (upa.conflicts > 0 || upa.missing > 0 ||
-		    upa.not_deleted > 0 || upa.unversioned > 0) {
-			if (upa.conflicts > 0) {
-				error = show_rebase_merge_conflict(&qid->id,
-				    repo);
-				if (error)
-					goto done;
-			}
-			got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
-			break;
-		}
-
-		error = rebase_commit(&merged_paths, worktree, fileindex,
-		    tmp_branch, committer, commit_id, 0, repo);
-		got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
-		if (error)
-			goto done;
-	}
-
-	if (upa.conflicts > 0 || upa.missing > 0 ||
-	    upa.not_deleted > 0 || upa.unversioned > 0) {
-		error = got_worktree_rebase_postpone(worktree, fileindex);
-		if (error)
-			goto done;
-		if (upa.conflicts > 0 && upa.missing == 0 &&
-		    upa.not_deleted == 0 && upa.unversioned == 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before rebasing "
-			    "can continue");
-		} else if (upa.conflicts > 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before rebasing "
-			    "can continue; changes destined for some "
-			    "files were not yet merged and should be "
-			    "merged manually if required before the "
-			    "rebase operation is continued");
-		} else {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "changes destined for some files were not "
-			    "yet merged and should be merged manually "
-			    "if required before the rebase operation "
-			    "is continued");
-		}
-	} else
-		error = rebase_complete(worktree, fileindex, branch,
-		    tmp_branch, repo, create_backup);
-done:
-	free(cwd);
-	free(committer);
-	free(gitconfig_path);
-	got_object_id_queue_free(&commits);
-	free(branch_head_commit_id);
-	free(resume_commit_id);
-	free(head_commit_id);
-	free(yca_id);
-	if (commit)
-		got_object_commit_close(commit);
-	if (branch)
-		got_ref_close(branch);
-	if (new_base_branch)
-		got_ref_close(new_base_branch);
-	if (tmp_branch)
-		got_ref_close(tmp_branch);
-	if (head_ref)
-		got_ref_close(head_ref);
-	if (worktree)
-		got_worktree_close(worktree);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	return error;
-}
-
-__dead static void
-usage_histedit(void)
-{
-	fprintf(stderr, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
-	    "[branch]\n", getprogname());
-	exit(1);
-}
-
-#define GOT_HISTEDIT_PICK 'p'
-#define GOT_HISTEDIT_EDIT 'e'
-#define GOT_HISTEDIT_FOLD 'f'
-#define GOT_HISTEDIT_DROP 'd'
-#define GOT_HISTEDIT_MESG 'm'
-
-static const struct got_histedit_cmd {
-	unsigned char code;
-	const char *name;
-	const char *desc;
-} got_histedit_cmds[] = {
-	{ GOT_HISTEDIT_PICK, "pick", "use commit" },
-	{ GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
-	{ GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
-	    "be used" },
-	{ GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
-	{ GOT_HISTEDIT_MESG, "mesg",
-	    "single-line log message for commit above (open editor if empty)" },
-};
-
-struct got_histedit_list_entry {
-	TAILQ_ENTRY(got_histedit_list_entry) entry;
-	struct got_object_id *commit_id;
-	const struct got_histedit_cmd *cmd;
-	char *logmsg;
-};
-TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
-
-static const struct got_error *
-histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
-    FILE *f, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	char *logmsg = NULL, *id_str = NULL;
-	struct got_commit_object *commit = NULL;
-	int n;
-
-	err = got_object_open_as_commit(&commit, repo, commit_id);
-	if (err)
-		goto done;
-
-	err = get_short_logmsg(&logmsg, 34, commit);
-	if (err)
-		goto done;
-
-	err = got_object_id_str(&id_str, commit_id);
-	if (err)
-		goto done;
-
-	n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
-	if (n < 0)
-		err = got_ferror(f, GOT_ERR_IO);
-done:
-	if (commit)
-		got_object_commit_close(commit);
-	free(id_str);
-	free(logmsg);
-	return err;
-}
-
-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 drop_only,
-    int edit_only, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_object_qid *qid;
-	const char *histedit_cmd = NULL;
-
-	if (STAILQ_EMPTY(commits))
-		return got_error(GOT_ERR_EMPTY_HISTEDIT);
-
-	STAILQ_FOREACH(qid, commits, entry) {
-		histedit_cmd = got_histedit_cmds[0].name;
-		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";
-		err = histedit_write_commit(&qid->id, histedit_cmd, f, repo);
-		if (err)
-			break;
-		if (edit_logmsg_only) {
-			int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
-			if (n < 0) {
-				err = got_ferror(f, GOT_ERR_IO);
-				break;
-			}
-		}
-	}
-
-	return err;
-}
-
-static const struct got_error *
-write_cmd_list(FILE *f, const char *branch_name,
-    struct got_object_id_queue *commits)
-{
-	const struct got_error *err = NULL;
-	size_t i;
-	int n;
-	char *id_str;
-	struct got_object_qid *qid;
-
-	qid = STAILQ_FIRST(commits);
-	err = got_object_id_str(&id_str, &qid->id);
-	if (err)
-		return err;
-
-	n = fprintf(f,
-	    "# Editing the history of branch '%s' starting at\n"
-	    "# commit %s\n"
-	    "# Commits will be processed in order from top to "
-	    "bottom of this file.\n", branch_name, id_str);
-	if (n < 0) {
-		err = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-
-	n = fprintf(f, "# Available histedit commands:\n");
-	if (n < 0) {
-		err = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-
-	for (i = 0; i < nitems(got_histedit_cmds); i++) {
-		const struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
-		n = fprintf(f, "#   %s (%c): %s\n", cmd->name, cmd->code,
-		    cmd->desc);
-		if (n < 0) {
-			err = got_ferror(f, GOT_ERR_IO);
-			break;
-		}
-	}
-done:
-	free(id_str);
-	return err;
-}
-
-static const struct got_error *
-histedit_syntax_error(int lineno)
-{
-	static char msg[42];
-	int ret;
-
-	ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
-	    lineno);
-	if (ret < 0 || (size_t)ret >= sizeof(msg))
-		return got_error(GOT_ERR_HISTEDIT_SYNTAX);
-
-	return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
-}
-
-static const struct got_error *
-append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
-    char *logmsg, struct got_repository *repo)
-{
-	const struct got_error *err;
-	struct got_commit_object *folded_commit = NULL;
-	char *id_str, *folded_logmsg = NULL;
-
-	err = got_object_id_str(&id_str, hle->commit_id);
-	if (err)
-		return err;
-
-	err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
-	if (err)
-		goto done;
-
-	err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
-	if (err)
-		goto done;
-	if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
-	    logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
-	    folded_logmsg) == -1) {
-		err = got_error_from_errno("asprintf");
-	}
-done:
-	if (folded_commit)
-		got_object_commit_close(folded_commit);
-	free(id_str);
-	free(folded_logmsg);
-	return err;
-}
-
-static struct got_histedit_list_entry *
-get_folded_commits(struct got_histedit_list_entry *hle)
-{
-	struct got_histedit_list_entry *prev, *folded = NULL;
-
-	prev = TAILQ_PREV(hle, got_histedit_list, entry);
-	while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
-	    prev->cmd->code == GOT_HISTEDIT_DROP)) {
-		if (prev->cmd->code == GOT_HISTEDIT_FOLD)
-			folded = prev;
-		prev = TAILQ_PREV(prev, got_histedit_list, entry);
-	}
-
-	return folded;
-}
-
-static const struct got_error *
-histedit_edit_logmsg(struct got_histedit_list_entry *hle,
-    struct got_repository *repo)
-{
-	char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
-	char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
-	const struct got_error *err = NULL;
-	struct got_commit_object *commit = NULL;
-	int logmsg_len;
-	int fd = -1;
-	struct got_histedit_list_entry *folded = NULL;
-
-	err = got_object_open_as_commit(&commit, repo, hle->commit_id);
-	if (err)
-		return err;
-
-	folded = get_folded_commits(hle);
-	if (folded) {
-		while (folded != hle) {
-			if (folded->cmd->code == GOT_HISTEDIT_DROP) {
-				folded = TAILQ_NEXT(folded, entry);
-				continue;
-			}
-			err = append_folded_commit_msg(&new_msg, folded,
-			    logmsg, repo);
-			if (err)
-				goto done;
-			free(logmsg);
-			logmsg = new_msg;
-			folded = TAILQ_NEXT(folded, entry);
-		}
-	}
-
-	err = got_object_id_str(&id_str, hle->commit_id);
-	if (err)
-		goto done;
-	err = got_object_commit_get_logmsg(&orig_logmsg, commit);
-	if (err)
-		goto done;
-	logmsg_len = asprintf(&new_msg,
-	    "%s\n# original log message of commit %s: %s",
-	    logmsg ? logmsg : "", id_str, orig_logmsg);
-	if (logmsg_len == -1) {
-		err = got_error_from_errno("asprintf");
-		goto done;
-	}
-	free(logmsg);
-	logmsg = new_msg;
-
-	err = got_object_id_str(&id_str, hle->commit_id);
-	if (err)
-		goto done;
-
-	err = got_opentemp_named_fd(&logmsg_path, &fd,
-	    GOT_TMPDIR_STR "/got-logmsg", "");
-	if (err)
-		goto done;
-
-	if (write(fd, logmsg, logmsg_len) == -1) {
-		err = got_error_from_errno2("write", logmsg_path);
-		goto done;
-	}
-	if (close(fd) == -1) {
-		err = got_error_from_errno2("close", logmsg_path);
-		goto done;
-	}
-	fd = -1;
-
-	err = get_editor(&editor);
-	if (err)
-		goto done;
-
-	err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
-	    logmsg_len, 0);
-	if (err) {
-		if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
-			goto done;
-		err = NULL;
-		hle->logmsg = strdup(new_msg);
-		if (hle->logmsg == NULL)
-			err = got_error_from_errno("strdup");
-	}
-done:
-	if (fd != -1 && close(fd) == -1 && err == NULL)
-		err = got_error_from_errno2("close", logmsg_path);
-	if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
-		err = got_error_from_errno2("unlink", logmsg_path);
-	free(logmsg_path);
-	free(logmsg);
-	free(orig_logmsg);
-	free(editor);
-	if (commit)
-		got_object_commit_close(commit);
-	return err;
-}
-
-static const struct got_error *
-histedit_parse_list(struct got_histedit_list *histedit_cmds,
-    FILE *f, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	char *line = NULL, *p, *end;
-	size_t i, linesize = 0;
-	ssize_t linelen;
-	int lineno = 0, lastcmd = -1;
-	const struct got_histedit_cmd *cmd;
-	struct got_object_id *commit_id = NULL;
-	struct got_histedit_list_entry *hle = NULL;
-
-	for (;;) {
-		linelen = getline(&line, &linesize, f);
-		if (linelen == -1) {
-			const struct got_error *getline_err;
-			if (feof(f))
-				break;
-			getline_err = got_error_from_errno("getline");
-			err = got_ferror(f, getline_err->code);
-			break;
-		}
-		lineno++;
-		p = line;
-		while (isspace((unsigned char)p[0]))
-			p++;
-		if (p[0] == '#' || p[0] == '\0')
-			continue;
-		cmd = NULL;
-		for (i = 0; i < nitems(got_histedit_cmds); i++) {
-			cmd = &got_histedit_cmds[i];
-			if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
-			    isspace((unsigned char)p[strlen(cmd->name)])) {
-				p += strlen(cmd->name);
-				break;
-			}
-			if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
-				p++;
-				break;
-			}
-		}
-		if (i == nitems(got_histedit_cmds)) {
-			err = histedit_syntax_error(lineno);
-			break;
-		}
-		while (isspace((unsigned char)p[0]))
-			p++;
-		if (cmd->code == GOT_HISTEDIT_MESG) {
-			if (lastcmd != GOT_HISTEDIT_PICK &&
-			    lastcmd != GOT_HISTEDIT_EDIT) {
-				err = got_error(GOT_ERR_HISTEDIT_CMD);
-				break;
-			}
-			if (p[0] == '\0') {
-				err = histedit_edit_logmsg(hle, repo);
-				if (err)
-					break;
-			} else {
-				hle->logmsg = strdup(p);
-				if (hle->logmsg == NULL) {
-					err = got_error_from_errno("strdup");
-					break;
-				}
-			}
-			lastcmd = cmd->code;
-			continue;
-		} else {
-			end = p;
-			while (end[0] && !isspace((unsigned char)end[0]))
-				end++;
-			*end = '\0';
-
-			err = got_object_resolve_id_str(&commit_id, repo, p);
-			if (err) {
-				/* override error code */
-				err = histedit_syntax_error(lineno);
-				break;
-			}
-		}
-		hle = malloc(sizeof(*hle));
-		if (hle == NULL) {
-			err = got_error_from_errno("malloc");
-			break;
-		}
-		hle->cmd = cmd;
-		hle->commit_id = commit_id;
-		hle->logmsg = NULL;
-		commit_id = NULL;
-		TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
-		lastcmd = cmd->code;
-	}
-
-	free(line);
-	free(commit_id);
-	return err;
-}
-
-static const struct got_error *
-histedit_check_script(struct got_histedit_list *histedit_cmds,
-    struct got_object_id_queue *commits, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_object_qid *qid;
-	struct got_histedit_list_entry *hle;
-	static char msg[92];
-	char *id_str;
-
-	if (TAILQ_EMPTY(histedit_cmds))
-		return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
-		    "histedit script contains no commands");
-	if (STAILQ_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);
-		}
-	}
-
-	STAILQ_FOREACH(qid, commits, entry) {
-		TAILQ_FOREACH(hle, histedit_cmds, entry) {
-			if (got_object_id_cmp(&qid->id, hle->commit_id) == 0)
-				break;
-		}
-		if (hle == NULL) {
-			err = got_object_id_str(&id_str, &qid->id);
-			if (err)
-				return err;
-			snprintf(msg, sizeof(msg),
-			    "commit %s missing from histedit script", id_str);
-			free(id_str);
-			return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
-		}
-	}
-
-	hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
-	if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
-		return got_error_msg(GOT_ERR_HISTEDIT_CMD,
-		    "last commit in histedit script cannot be folded");
-
-	return NULL;
-}
-
-static const struct got_error *
-histedit_run_editor(struct got_histedit_list *histedit_cmds,
-    const char *path, struct got_object_id_queue *commits,
-    struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	char *editor;
-	FILE *f = NULL;
-
-	err = get_editor(&editor);
-	if (err)
-		return err;
-
-	if (spawn_editor(editor, path) == -1) {
-		err = got_error_from_errno("failed spawning editor");
-		goto done;
-	}
-
-	f = fopen(path, "re");
-	if (f == NULL) {
-		err = got_error_from_errno("fopen");
-		goto done;
-	}
-	err = histedit_parse_list(histedit_cmds, f, repo);
-	if (err)
-		goto done;
-
-	err = histedit_check_script(histedit_cmds, commits, repo);
-done:
-	if (f && fclose(f) == EOF && err == NULL)
-		err = got_error_from_errno("fclose");
-	free(editor);
-	return err;
-}
-
-static const struct got_error *
-histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
-    struct got_object_id_queue *, const char *, const char *,
-    struct got_repository *);
-
-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 drop_only, int edit_only,
-    struct got_repository *repo)
-{
-	const struct got_error *err;
-	FILE *f = NULL;
-	char *path = NULL;
-
-	err = got_opentemp_named(&path, &f, "got-histedit", "");
-	if (err)
-		return err;
-
-	err = write_cmd_list(f, branch_name, commits);
-	if (err)
-		goto done;
-
-	err = histedit_write_commit_list(commits, f, edit_logmsg_only,
-	    fold_only, drop_only, edit_only, repo);
-	if (err)
-		goto done;
-
-	if (drop_only || edit_logmsg_only || fold_only || edit_only) {
-		rewind(f);
-		err = histedit_parse_list(histedit_cmds, f, repo);
-	} else {
-		if (fclose(f) == EOF) {
-			err = got_error_from_errno("fclose");
-			goto done;
-		}
-		f = NULL;
-		err = histedit_run_editor(histedit_cmds, path, commits, repo);
-		if (err) {
-			if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
-			    err->code != GOT_ERR_HISTEDIT_CMD)
-				goto done;
-			err = histedit_edit_list_retry(histedit_cmds, err,
-			    commits, path, branch_name, repo);
-		}
-	}
-done:
-	if (f && fclose(f) == EOF && err == NULL)
-		err = got_error_from_errno("fclose");
-	if (path && unlink(path) != 0 && err == NULL)
-		err = got_error_from_errno2("unlink", path);
-	free(path);
-	return err;
-}
-
-static const struct got_error *
-histedit_save_list(struct got_histedit_list *histedit_cmds,
-    struct got_worktree *worktree, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	char *path = NULL;
-	FILE *f = NULL;
-	struct got_histedit_list_entry *hle;
-	struct got_commit_object *commit = NULL;
-
-	err = got_worktree_get_histedit_script_path(&path, worktree);
-	if (err)
-		return err;
-
-	f = fopen(path, "we");
-	if (f == NULL) {
-		err = got_error_from_errno2("fopen", path);
-		goto done;
-	}
-	TAILQ_FOREACH(hle, histedit_cmds, entry) {
-		err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
-		    repo);
-		if (err)
-			break;
-
-		if (hle->logmsg) {
-			int n = fprintf(f, "%c %s\n",
-			    GOT_HISTEDIT_MESG, hle->logmsg);
-			if (n < 0) {
-				err = got_ferror(f, GOT_ERR_IO);
-				break;
-			}
-		}
-	}
-done:
-	if (f && fclose(f) == EOF && err == NULL)
-		err = got_error_from_errno("fclose");
-	free(path);
-	if (commit)
-		got_object_commit_close(commit);
-	return err;
-}
-
-static void
-histedit_free_list(struct got_histedit_list *histedit_cmds)
-{
-	struct got_histedit_list_entry *hle;
-
-	while ((hle = TAILQ_FIRST(histedit_cmds))) {
-		TAILQ_REMOVE(histedit_cmds, hle, entry);
-		free(hle);
-	}
-}
-
-static const struct got_error *
-histedit_load_list(struct got_histedit_list *histedit_cmds,
-    const char *path, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	FILE *f = NULL;
-
-	f = fopen(path, "re");
-	if (f == NULL) {
-		err = got_error_from_errno2("fopen", path);
-		goto done;
-	}
-
-	err = histedit_parse_list(histedit_cmds, f, repo);
-done:
-	if (f && fclose(f) == EOF && err == NULL)
-		err = got_error_from_errno("fclose");
-	return err;
-}
-
-static const struct got_error *
-histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
-    const struct got_error *edit_err, struct got_object_id_queue *commits,
-    const char *path, const char *branch_name, struct got_repository *repo)
-{
-	const struct got_error *err = NULL, *prev_err = edit_err;
-	int resp = ' ';
-
-	while (resp != 'c' && resp != 'r' && resp != 'a') {
-		printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
-		    "or (a)bort: ", getprogname(), prev_err->msg);
-		resp = getchar();
-		if (resp == '\n')
-			resp = getchar();
-		if (resp == 'c') {
-			histedit_free_list(histedit_cmds);
-			err = histedit_run_editor(histedit_cmds, path, commits,
-			    repo);
-			if (err) {
-				if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
-				    err->code != GOT_ERR_HISTEDIT_CMD)
-					break;
-				prev_err = err;
-				resp = ' ';
-				continue;
-			}
-			break;
-		} else if (resp == 'r') {
-			histedit_free_list(histedit_cmds);
-			err = histedit_edit_script(histedit_cmds,
-			    commits, branch_name, 0, 0, 0, 0, repo);
-			if (err) {
-				if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
-				    err->code != GOT_ERR_HISTEDIT_CMD)
-					break;
-				prev_err = err;
-				resp = ' ';
-				continue;
-			}
-			break;
-		} else if (resp == 'a') {
-			err = got_error(GOT_ERR_HISTEDIT_CANCEL);
-			break;
-		} else
-			printf("invalid response '%c'\n", resp);
-	}
-
-	return err;
-}
-
-static const struct got_error *
-histedit_complete(struct got_worktree *worktree,
-    struct got_fileindex *fileindex, struct got_reference *tmp_branch,
-    struct got_reference *branch, struct got_repository *repo)
-{
-	printf("Switching work tree to %s\n",
-	    got_ref_get_symref_target(branch));
-	return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
-	    branch, repo);
-}
-
-static const struct got_error *
-show_histedit_progress(struct got_commit_object *commit,
-    struct got_histedit_list_entry *hle, struct got_object_id *new_id)
-{
-	const struct got_error *err;
-	char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
-
-	err = got_object_id_str(&old_id_str, hle->commit_id);
-	if (err)
-		goto done;
-
-	if (new_id) {
-		err = got_object_id_str(&new_id_str, new_id);
-		if (err)
-			goto done;
-	}
-
-	old_id_str[12] = '\0';
-	if (new_id_str)
-		new_id_str[12] = '\0';
-
-	if (hle->logmsg) {
-		logmsg = strdup(hle->logmsg);
-		if (logmsg == NULL) {
-			err = got_error_from_errno("strdup");
-			goto done;
-		}
-		trim_logmsg(logmsg, 42);
-	} else {
-		err = get_short_logmsg(&logmsg, 42, commit);
-		if (err)
-			goto done;
-	}
-
-	switch (hle->cmd->code) {
-	case GOT_HISTEDIT_PICK:
-	case GOT_HISTEDIT_EDIT:
-		printf("%s -> %s: %s\n", old_id_str,
-		    new_id_str ? new_id_str : "no-op change", logmsg);
-		break;
-	case GOT_HISTEDIT_DROP:
-	case GOT_HISTEDIT_FOLD:
-		printf("%s ->  %s commit: %s\n", old_id_str, hle->cmd->name,
-		    logmsg);
-		break;
-	default:
-		break;
-	}
-done:
-	free(old_id_str);
-	free(new_id_str);
-	return err;
-}
-
-static const struct got_error *
-histedit_commit(struct got_pathlist_head *merged_paths,
-    struct got_worktree *worktree, struct got_fileindex *fileindex,
-    struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
-    const char *committer, int allow_conflict, struct got_repository *repo)
-{
-	const struct got_error *err;
-	struct got_commit_object *commit;
-	struct got_object_id *new_commit_id;
-
-	if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
-	    && hle->logmsg == NULL) {
-		err = histedit_edit_logmsg(hle, repo);
-		if (err)
-			return err;
-	}
-
-	err = got_object_open_as_commit(&commit, repo, hle->commit_id);
-	if (err)
-		return err;
-
-	err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
-	    worktree, fileindex, tmp_branch, committer, commit, hle->commit_id,
-	    hle->logmsg, allow_conflict, repo);
-	if (err) {
-		if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
-			goto done;
-		err = show_histedit_progress(commit, hle, NULL);
-	} else {
-		err = show_histedit_progress(commit, hle, new_commit_id);
-		free(new_commit_id);
-	}
-done:
-	got_object_commit_close(commit);
-	return err;
-}
-
-static const struct got_error *
-histedit_skip_commit(struct got_histedit_list_entry *hle,
-    struct got_worktree *worktree, struct got_repository *repo)
-{
-	const struct got_error *error;
-	struct got_commit_object *commit;
-
-	error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
-	    repo);
-	if (error)
-		return error;
-
-	error = got_object_open_as_commit(&commit, repo, hle->commit_id);
-	if (error)
-		return error;
-
-	error = show_histedit_progress(commit, hle, NULL);
-	got_object_commit_close(commit);
-	return error;
-}
-
-static const struct got_error *
-check_local_changes(void *arg, unsigned char status,
-    unsigned char staged_status, const char *path,
-    struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
-    struct got_object_id *commit_id, int dirfd, const char *de_name)
-{
-	int *have_local_changes = arg;
-
-	switch (status) {
-	case GOT_STATUS_ADD:
-	case GOT_STATUS_DELETE:
-	case GOT_STATUS_MODIFY:
-	case GOT_STATUS_CONFLICT:
-		*have_local_changes = 1;
-		return got_error(GOT_ERR_CANCELLED);
-	default:
-		break;
-	}
-
-	switch (staged_status) {
-	case GOT_STATUS_ADD:
-	case GOT_STATUS_DELETE:
-	case GOT_STATUS_MODIFY:
-		*have_local_changes = 1;
-		return got_error(GOT_ERR_CANCELLED);
-	default:
-		break;
-	}
-
-	return NULL;
-}
-
-static const struct got_error *
-cmd_histedit(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_worktree *worktree = NULL;
-	struct got_fileindex *fileindex = NULL;
-	struct got_repository *repo = NULL;
-	char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
-	struct got_reference *branch = NULL;
-	struct got_reference *tmp_branch = NULL;
-	struct got_object_id *resume_commit_id = NULL;
-	struct got_object_id *base_commit_id = NULL;
-	struct got_object_id *head_commit_id = NULL;
-	struct got_commit_object *commit = NULL;
-	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 drop_only = 0, edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
-	int allow_conflict = 0, list_backups = 0, delete_backups = 0;
-	const char *edit_script_path = NULL;
-	struct got_object_id_queue commits;
-	struct got_pathlist_head merged_paths;
-	const struct got_object_id_queue *parent_ids;
-	struct got_object_qid *pid;
-	struct got_histedit_list histedit_cmds;
-	struct got_histedit_list_entry *hle;
-	int *pack_fds = NULL;
-
-	STAILQ_INIT(&commits);
-	TAILQ_INIT(&histedit_cmds);
-	TAILQ_INIT(&merged_paths);
-	memset(&upa, 0, sizeof(upa));
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "aCcdeF:flmX")) != -1) {
-		switch (ch) {
-		case 'a':
-			abort_edit = 1;
-			break;
-		case 'C':
-			allow_conflict = 1;
-			break;
-		case 'c':
-			continue_edit = 1;
-			break;
-		case 'd':
-			drop_only = 1;
-			break;
-		case 'e':
-			edit_only = 1;
-			break;
-		case 'F':
-			edit_script_path = optarg;
-			break;
-		case 'f':
-			fold_only = 1;
-			break;
-		case 'l':
-			list_backups = 1;
-			break;
-		case 'm':
-			edit_logmsg_only = 1;
-			break;
-		case 'X':
-			delete_backups = 1;
-			break;
-		default:
-			usage_histedit();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (abort_edit && allow_conflict)
-		option_conflict('a', 'C');
-	if (abort_edit && continue_edit)
-		option_conflict('a', 'c');
-	if (edit_script_path && allow_conflict)
-		option_conflict('F', 'C');
-	if (edit_script_path && edit_logmsg_only)
-		option_conflict('F', 'm');
-	if (abort_edit && edit_logmsg_only)
-		option_conflict('a', 'm');
-	if (edit_logmsg_only && allow_conflict)
-		option_conflict('m', 'C');
-	if (continue_edit && edit_logmsg_only)
-		option_conflict('c', 'm');
-	if (abort_edit && fold_only)
-		option_conflict('a', 'f');
-	if (fold_only && allow_conflict)
-		option_conflict('f', 'C');
-	if (continue_edit && fold_only)
-		option_conflict('c', 'f');
-	if (fold_only && edit_logmsg_only)
-		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 (fold_only && edit_only)
-		option_conflict('f', 'e');
-	if (drop_only && abort_edit)
-		option_conflict('d', 'a');
-	if (drop_only && allow_conflict)
-		option_conflict('d', 'C');
-	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');
-		if (allow_conflict)
-			option_conflict('l', 'C');
-		if (continue_edit)
-			option_conflict('l', 'c');
-		if (edit_script_path)
-			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)
-			option_conflict('l', 'e');
-		if (delete_backups)
-			option_conflict('l', 'X');
-		if (argc != 0 && argc != 1)
-			usage_histedit();
-	} else if (delete_backups) {
-		if (abort_edit)
-			option_conflict('X', 'a');
-		if (allow_conflict)
-			option_conflict('X', 'C');
-		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)
-			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)
-			usage_histedit();
-	} else if (allow_conflict && !continue_edit)
-		errx(1, "-C option requires -c");
-	else if (argc != 0)
-		usage_histedit();
-
-	/*
-	 * This command cannot apply unveil(2) in all cases because the
-	 * user may choose to run an editor to edit the histedit script
-	 * and to edit individual commit log messages.
-	 * unveil(2) traverses exec(2); if an editor is used we have to
-	 * apply unveil after edit script and log messages have been written.
-	 * XXX TODO: Make use of unveil(2) where possible.
-	 */
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (list_backups || delete_backups) {
-			if (error->code != GOT_ERR_NOT_WORKTREE)
-				goto done;
-		} else {
-			if (error->code == GOT_ERR_NOT_WORKTREE)
-				error = wrap_not_worktree_error(error,
-				    "histedit", cwd);
-			goto done;
-		}
-	}
-
-	if (list_backups || delete_backups) {
-		error = got_repo_open(&repo,
-		    worktree ? got_worktree_get_repo_path(worktree) : cwd,
-		    NULL, pack_fds);
-		if (error != NULL)
-			goto done;
-		error = apply_unveil(got_repo_get_path(repo), 0,
-		    worktree ? got_worktree_get_root_path(worktree) : NULL);
-		if (error)
-			goto done;
-		error = process_backup_refs(
-		    GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
-		    argc == 1 ? argv[0] : NULL, delete_backups, repo);
-		goto done; /* nothing else to do */
-	}
-
-	error = get_gitconfig_path(&gitconfig_path);
-	if (error)
-		goto done;
-	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
-	    gitconfig_path, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (worktree != NULL && !list_backups && !delete_backups) {
-		error = worktree_has_logmsg_ref("histedit", worktree, repo);
-		if (error)
-			goto done;
-	}
-
-	error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
-	if (error)
-		goto done;
-	if (rebase_in_progress) {
-		error = got_error(GOT_ERR_REBASING);
-		goto done;
-	}
-
-	error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
-	    repo);
-	if (error)
-		goto done;
-	if (merge_in_progress) {
-		error = got_error(GOT_ERR_MERGE_BUSY);
-		goto done;
-	}
-
-	error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
-	if (error)
-		goto done;
-
-	if (edit_in_progress && edit_logmsg_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 -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 "
-		    "work tree and must be continued or aborted "
-		    "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,
-		    &tmp_branch, &branch, &base_commit_id, &fileindex,
-		    worktree, repo);
-		if (error)
-			goto done;
-		printf("Switching work tree to %s\n",
-		    got_ref_get_symref_target(branch));
-		error = got_worktree_histedit_abort(worktree, fileindex, repo,
-		    branch, base_commit_id, abort_progress, &upa);
-		if (error)
-			goto done;
-		printf("Histedit of %s aborted\n",
-		    got_ref_get_symref_target(branch));
-		print_merge_progress_stats(&upa);
-		goto done; /* nothing else to do */
-	} else if (abort_edit) {
-		error = got_error(GOT_ERR_NOT_HISTEDIT);
-		goto done;
-	}
-
-	error = get_author(&committer, repo, worktree);
-	if (error)
-		goto done;
-
-	if (continue_edit) {
-		char *path;
-
-		if (!edit_in_progress) {
-			error = got_error(GOT_ERR_NOT_HISTEDIT);
-			goto done;
-		}
-
-		error = got_worktree_get_histedit_script_path(&path, worktree);
-		if (error)
-			goto done;
-
-		error = histedit_load_list(&histedit_cmds, path, repo);
-		free(path);
-		if (error)
-			goto done;
-
-		error = got_worktree_histedit_continue(&resume_commit_id,
-		    &tmp_branch, &branch, &base_commit_id, &fileindex,
-		    worktree, repo);
-		if (error)
-			goto done;
-
-		error = got_ref_resolve(&head_commit_id, repo, branch);
-		if (error)
-			goto done;
-
-		error = got_object_open_as_commit(&commit, repo,
-		    head_commit_id);
-		if (error)
-			goto done;
-		parent_ids = got_object_commit_get_parent_ids(commit);
-		pid = STAILQ_FIRST(parent_ids);
-		if (pid == NULL) {
-			error = got_error(GOT_ERR_EMPTY_HISTEDIT);
-			goto done;
-		}
-		error = collect_commits(&commits, head_commit_id, &pid->id,
-		    base_commit_id, got_worktree_get_path_prefix(worktree),
-		    GOT_ERR_HISTEDIT_PATH, repo);
-		got_object_commit_close(commit);
-		commit = NULL;
-		if (error)
-			goto done;
-	} else {
-		if (edit_in_progress) {
-			error = got_error(GOT_ERR_HISTEDIT_BUSY);
-			goto done;
-		}
-
-		error = got_ref_open(&branch, repo,
-		    got_worktree_get_head_ref_name(worktree), 0);
-		if (error != NULL)
-			goto done;
-
-		if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
-			error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
-			    "will not edit commit history of a branch outside "
-			    "the \"refs/heads/\" reference namespace");
-			goto done;
-		}
-
-		error = got_ref_resolve(&head_commit_id, repo, branch);
-		got_ref_close(branch);
-		branch = NULL;
-		if (error)
-			goto done;
-
-		error = got_object_open_as_commit(&commit, repo,
-		    head_commit_id);
-		if (error)
-			goto done;
-		parent_ids = got_object_commit_get_parent_ids(commit);
-		pid = STAILQ_FIRST(parent_ids);
-		if (pid == NULL) {
-			error = got_error(GOT_ERR_EMPTY_HISTEDIT);
-			goto done;
-		}
-		error = collect_commits(&commits, head_commit_id, &pid->id,
-		    got_worktree_get_base_commit_id(worktree),
-		    got_worktree_get_path_prefix(worktree),
-		    GOT_ERR_HISTEDIT_PATH, repo);
-		got_object_commit_close(commit);
-		commit = NULL;
-		if (error)
-			goto done;
-
-		if (STAILQ_EMPTY(&commits)) {
-			error = got_error(GOT_ERR_EMPTY_HISTEDIT);
-			goto done;
-		}
-
-		error = got_worktree_histedit_prepare(&tmp_branch, &branch,
-		    &base_commit_id, &fileindex, worktree, repo);
-		if (error)
-			goto done;
-
-		if (edit_script_path) {
-			error = histedit_load_list(&histedit_cmds,
-			    edit_script_path, repo);
-			if (error) {
-				got_worktree_histedit_abort(worktree, fileindex,
-				    repo, branch, base_commit_id,
-				    abort_progress, &upa);
-				print_merge_progress_stats(&upa);
-				goto done;
-			}
-		} else {
-			const char *branch_name;
-			branch_name = got_ref_get_symref_target(branch);
-			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,
-			    drop_only, edit_only, repo);
-			if (error) {
-				got_worktree_histedit_abort(worktree, fileindex,
-				    repo, branch, base_commit_id,
-				    abort_progress, &upa);
-				print_merge_progress_stats(&upa);
-				goto done;
-			}
-
-		}
-
-		error = histedit_save_list(&histedit_cmds, worktree,
-		    repo);
-		if (error) {
-			got_worktree_histedit_abort(worktree, fileindex,
-			    repo, branch, base_commit_id,
-			    abort_progress, &upa);
-			print_merge_progress_stats(&upa);
-			goto done;
-		}
-
-	}
-
-	error = histedit_check_script(&histedit_cmds, &commits, repo);
-	if (error)
-		goto done;
-
-	TAILQ_FOREACH(hle, &histedit_cmds, entry) {
-		if (resume_commit_id) {
-			if (got_object_id_cmp(hle->commit_id,
-			    resume_commit_id) != 0)
-				continue;
-
-			resume_commit_id = NULL;
-			if (hle->cmd->code == GOT_HISTEDIT_DROP ||
-			    hle->cmd->code == GOT_HISTEDIT_FOLD) {
-				error = histedit_skip_commit(hle, worktree,
-				    repo);
-				if (error)
-					goto done;
-			} else {
-				struct got_pathlist_head paths;
-				int have_changes = 0;
-
-				TAILQ_INIT(&paths);
-				error = got_pathlist_append(&paths, "", NULL);
-				if (error)
-					goto done;
-				error = got_worktree_status(worktree, &paths,
-				    repo, 0, check_local_changes, &have_changes,
-				    check_cancelled, NULL);
-				got_pathlist_free(&paths,
-				    GOT_PATHLIST_FREE_NONE);
-				if (error) {
-					if (error->code != GOT_ERR_CANCELLED)
-						goto done;
-					if (sigint_received || sigpipe_received)
-						goto done;
-				}
-				if (have_changes) {
-					error = histedit_commit(NULL, worktree,
-					    fileindex, tmp_branch, hle,
-					    committer, allow_conflict, repo);
-					if (error)
-						goto done;
-				} else {
-					error = got_object_open_as_commit(
-					    &commit, repo, hle->commit_id);
-					if (error)
-						goto done;
-					error = show_histedit_progress(commit,
-					    hle, NULL);
-					got_object_commit_close(commit);
-					commit = NULL;
-					if (error)
-						goto done;
-				}
-			}
-			continue;
-		}
-
-		if (hle->cmd->code == GOT_HISTEDIT_DROP) {
-			error = histedit_skip_commit(hle, worktree, repo);
-			if (error)
-				goto done;
-			continue;
-		}
-
-		error = got_object_open_as_commit(&commit, repo,
-		    hle->commit_id);
-		if (error)
-			goto done;
-		parent_ids = got_object_commit_get_parent_ids(commit);
-		pid = STAILQ_FIRST(parent_ids);
-
-		error = got_worktree_histedit_merge_files(&merged_paths,
-		    worktree, fileindex, &pid->id, hle->commit_id, repo,
-		    update_progress, &upa, check_cancelled, NULL);
-		if (error)
-			goto done;
-		got_object_commit_close(commit);
-		commit = NULL;
-
-		print_merge_progress_stats(&upa);
-		if (upa.conflicts > 0 || upa.missing > 0 ||
-		    upa.not_deleted > 0 || upa.unversioned > 0) {
-			if (upa.conflicts > 0) {
-				error = show_rebase_merge_conflict(
-				    hle->commit_id, repo);
-				if (error)
-					goto done;
-			}
-			got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
-			break;
-		}
-
-		if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
-			char *id_str;
-			error = got_object_id_str(&id_str, hle->commit_id);
-			if (error)
-				goto done;
-			printf("Stopping histedit for amending commit %s\n",
-			    id_str);
-			free(id_str);
-			got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
-			error = got_worktree_histedit_postpone(worktree,
-			    fileindex);
-			goto done;
-		}
-
-		if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
-			error = histedit_skip_commit(hle, worktree, repo);
-			if (error)
-				goto done;
-			continue;
-		}
-
-		error = histedit_commit(&merged_paths, worktree, fileindex,
-		    tmp_branch, hle, committer, allow_conflict, repo);
-		got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
-		if (error)
-			goto done;
-	}
-
-	if (upa.conflicts > 0 || upa.missing > 0 ||
-	    upa.not_deleted > 0 || upa.unversioned > 0) {
-		error = got_worktree_histedit_postpone(worktree, fileindex);
-		if (error)
-			goto done;
-		if (upa.conflicts > 0 && upa.missing == 0 &&
-		    upa.not_deleted == 0 && upa.unversioned == 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before histedit "
-			    "can continue");
-		} else if (upa.conflicts > 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before histedit "
-			    "can continue; changes destined for some "
-			    "files were not yet merged and should be "
-			    "merged manually if required before the "
-			    "histedit operation is continued");
-		} else {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "changes destined for some files were not "
-			    "yet merged and should be merged manually "
-			    "if required before the histedit operation "
-			    "is continued");
-		}
-	} else
-		error = histedit_complete(worktree, fileindex, tmp_branch,
-		    branch, repo);
-done:
-	free(cwd);
-	free(committer);
-	free(gitconfig_path);
-	got_object_id_queue_free(&commits);
-	histedit_free_list(&histedit_cmds);
-	free(head_commit_id);
-	free(base_commit_id);
-	free(resume_commit_id);
-	if (commit)
-		got_object_commit_close(commit);
-	if (branch)
-		got_ref_close(branch);
-	if (tmp_branch)
-		got_ref_close(tmp_branch);
-	if (worktree)
-		got_worktree_close(worktree);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	return error;
-}
-
-__dead static void
-usage_integrate(void)
-{
-	fprintf(stderr, "usage: %s integrate branch\n", getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-cmd_integrate(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_repository *repo = NULL;
-	struct got_worktree *worktree = NULL;
-	char *cwd = NULL, *refname = NULL, *base_refname = NULL;
-	const char *branch_arg = NULL;
-	struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
-	struct got_fileindex *fileindex = NULL;
-	struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
-	int ch;
-	struct got_update_progress_arg upa;
-	int *pack_fds = NULL;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "")) != -1) {
-		switch (ch) {
-		default:
-			usage_integrate();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (argc != 1)
-		usage_integrate();
-	branch_arg = argv[0];
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (error->code == GOT_ERR_NOT_WORKTREE)
-			error = wrap_not_worktree_error(error, "integrate",
-			    cwd);
-		goto done;
-	}
-
-	error = check_rebase_or_histedit_in_progress(worktree);
-	if (error)
-		goto done;
-
-	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
-	    NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    got_worktree_get_root_path(worktree));
-	if (error)
-		goto done;
-
-	error = check_merge_in_progress(worktree, repo);
-	if (error)
-		goto done;
-
-	if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
-		error = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
-	    &base_branch_ref, worktree, refname, repo);
-	if (error)
-		goto done;
-
-	refname = strdup(got_ref_get_name(branch_ref));
-	if (refname == NULL) {
-		error = got_error_from_errno("strdup");
-		got_worktree_integrate_abort(worktree, fileindex, repo,
-		    branch_ref, base_branch_ref);
-		goto done;
-	}
-	base_refname = strdup(got_ref_get_name(base_branch_ref));
-	if (base_refname == NULL) {
-		error = got_error_from_errno("strdup");
-		got_worktree_integrate_abort(worktree, fileindex, repo,
-		    branch_ref, base_branch_ref);
-		goto done;
-	}
-	if (strncmp(base_refname, "refs/heads/", 11) != 0) {
-		error = got_error(GOT_ERR_INTEGRATE_BRANCH);
-		got_worktree_integrate_abort(worktree, fileindex, repo,
-		    branch_ref, base_branch_ref);
-		goto done;
-	}
-
-	error = got_ref_resolve(&commit_id, repo, branch_ref);
-	if (error)
-		goto done;
-
-	error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
-	if (error)
-		goto done;
-
-	if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
-		error = got_error_msg(GOT_ERR_SAME_BRANCH,
-		    "specified branch has already been integrated");
-		got_worktree_integrate_abort(worktree, fileindex, repo,
-		    branch_ref, base_branch_ref);
-		goto done;
-	}
-
-	error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
-	if (error) {
-		if (error->code == GOT_ERR_ANCESTRY)
-			error = got_error(GOT_ERR_REBASE_REQUIRED);
-		got_worktree_integrate_abort(worktree, fileindex, repo,
-		    branch_ref, base_branch_ref);
-		goto done;
-	}
-
-	memset(&upa, 0, sizeof(upa));
-	error = got_worktree_integrate_continue(worktree, fileindex, repo,
-	    branch_ref, base_branch_ref, update_progress, &upa,
-	    check_cancelled, NULL);
-	if (error)
-		goto done;
-
-	printf("Integrated %s into %s\n", refname, base_refname);
-	print_update_progress_stats(&upa);
-done:
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (worktree)
-		got_worktree_close(worktree);
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	free(cwd);
-	free(base_commit_id);
-	free(commit_id);
-	free(refname);
-	free(base_refname);
-	return error;
-}
-
-__dead static void
-usage_merge(void)
-{
-	fprintf(stderr, "usage: %s merge [-aCcn] [branch]\n", getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-cmd_merge(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_worktree *worktree = NULL;
-	struct got_repository *repo = NULL;
-	struct got_fileindex *fileindex = NULL;
-	char *cwd = NULL, *id_str = NULL, *author = NULL;
-	char *gitconfig_path = NULL;
-	struct got_reference *branch = NULL, *wt_branch = NULL;
-	struct got_object_id *branch_tip = NULL, *yca_id = NULL;
-	struct got_object_id *wt_branch_tip = NULL;
-	int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
-	int allow_conflict = 0, prefer_fast_forward = 1, interrupt_merge = 0;
-	struct got_update_progress_arg upa;
-	struct got_object_id *merge_commit_id = NULL;
-	char *branch_name = NULL;
-	int *pack_fds = NULL;
-
-	memset(&upa, 0, sizeof(upa));
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "aCcMn")) != -1) {
-		switch (ch) {
-		case 'a':
-			abort_merge = 1;
-			break;
-		case 'C':
-			allow_conflict = 1;
-			break;
-		case 'c':
-			continue_merge = 1;
-			break;
-		case 'M':
-			prefer_fast_forward = 0;
-			break;
-		case 'n':
-			interrupt_merge = 1;
-			break;
-		default:
-			usage_merge();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (abort_merge) {
-		if (continue_merge)
-			option_conflict('a', 'c');
-		if (!prefer_fast_forward)
-			option_conflict('a', 'M');
-		if (interrupt_merge)
-			option_conflict('a', 'n');
-	} else if (continue_merge) {
-		if (!prefer_fast_forward)
-			option_conflict('c', 'M');
-		if (interrupt_merge)
-			option_conflict('c', 'n');
-	}
-	if (allow_conflict) {
-		if (!continue_merge)
-			errx(1, "-C option requires -c");
-	}
-	if (abort_merge || continue_merge) {
-		if (argc != 0)
-			usage_merge();
-	} else if (argc != 1)
-		usage_merge();
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (error->code == GOT_ERR_NOT_WORKTREE)
-			error = wrap_not_worktree_error(error,
-			    "merge", cwd);
-		goto done;
-	}
-
-	error = get_gitconfig_path(&gitconfig_path);
-	if (error)
-		goto done;
-	error = got_repo_open(&repo,
-	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
-	    gitconfig_path, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (worktree != NULL) {
-		error = worktree_has_logmsg_ref("merge", worktree, repo);
-		if (error)
-			goto done;
-	}
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    worktree ? got_worktree_get_root_path(worktree) : NULL);
-	if (error)
-		goto done;
-
-	error = check_rebase_or_histedit_in_progress(worktree);
-	if (error)
-		goto done;
-
-	error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
-	    repo);
-	if (error)
-		goto done;
-
-	if (merge_in_progress && !(abort_merge || continue_merge)) {
-		error = got_error(GOT_ERR_MERGE_BUSY);
-		goto done;
-	}
-
-	if (!merge_in_progress && (abort_merge || continue_merge)) {
-		error = got_error(GOT_ERR_NOT_MERGING);
-		goto done;
-	}
-
-	if (abort_merge) {
-		error = got_worktree_merge_continue(&branch_name,
-		    &branch_tip, &fileindex, worktree, repo);
-		if (error)
-			goto done;
-		error = got_worktree_merge_abort(worktree, fileindex, repo,
-		    abort_progress, &upa);
-		if (error)
-			goto done;
-		printf("Merge of %s aborted\n", branch_name);
-		goto done; /* nothing else to do */
-	}
-
-	if (strncmp(got_worktree_get_head_ref_name(worktree),
-	    "refs/heads/", 11) != 0) {
-		error = got_error_fmt(GOT_ERR_COMMIT_BRANCH,
-		    "work tree's current branch %s is outside the "
-		    "\"refs/heads/\" reference namespace; "
-		    "update -b required",
-		    got_worktree_get_head_ref_name(worktree));
-		goto done;
-	}
-
-	error = get_author(&author, repo, worktree);
-	if (error)
-		goto done;
-
-	error = got_ref_open(&wt_branch, repo,
-	    got_worktree_get_head_ref_name(worktree), 0);
-	if (error)
-		goto done;
-	error = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
-	if (error)
-		goto done;
-
-	if (continue_merge) {
-		struct got_object_id *base_commit_id;
-		base_commit_id = got_worktree_get_base_commit_id(worktree);
-		if (got_object_id_cmp(wt_branch_tip, base_commit_id) != 0) {
-			error = got_error(GOT_ERR_MERGE_COMMIT_OUT_OF_DATE);
-			goto done;
-		}
-		error = got_worktree_merge_continue(&branch_name,
-		    &branch_tip, &fileindex, worktree, repo);
-		if (error)
-			goto done;
-	} else {
-		error = got_ref_open(&branch, repo, argv[0], 0);
-		if (error != NULL)
-			goto done;
-		branch_name = strdup(got_ref_get_name(branch));
-		if (branch_name == NULL) {
-			error = got_error_from_errno("strdup");
-			goto done;
-		}
-		error = got_ref_resolve(&branch_tip, repo, branch);
-		if (error)
-			goto done;
-	}
-
-	error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
-	    wt_branch_tip, branch_tip, 0, repo,
-	    check_cancelled, NULL);
-	if (error && error->code != GOT_ERR_ANCESTRY)
-		goto done;
-
-	if (!continue_merge) {
-		error = check_path_prefix(wt_branch_tip, branch_tip,
-		    got_worktree_get_path_prefix(worktree),
-		    GOT_ERR_MERGE_PATH, repo);
-		if (error)
-			goto done;
-		error = got_worktree_merge_prepare(&fileindex, worktree, repo);
-		if (error)
-			goto done;
-		if (prefer_fast_forward && yca_id &&
-		    got_object_id_cmp(wt_branch_tip, yca_id) == 0) {
-			struct got_pathlist_head paths;
-			if (interrupt_merge) {
-				error = got_error_fmt(GOT_ERR_BAD_OPTION,
-				    "there are no changes to merge since %s "
-				    "is already based on %s; merge cannot be "
-				    "interrupted for amending; -n",
-				    branch_name, got_ref_get_name(wt_branch));
-				goto done;
-			}
-			printf("Forwarding %s to %s\n",
-				got_ref_get_name(wt_branch), branch_name);
-			error = got_ref_change_ref(wt_branch, branch_tip);
-			if (error)
-				goto done;
-			error = got_ref_write(wt_branch, repo);
-			if (error)
-				goto done;
-			error = got_worktree_set_base_commit_id(worktree, repo,
-			    branch_tip);
-			if (error)
-				goto done;
-			TAILQ_INIT(&paths);
-			error = got_pathlist_append(&paths, "", NULL);
-			if (error)
-				goto done;
-			error = got_worktree_checkout_files(worktree,
-			    &paths, repo, update_progress, &upa,
-			    check_cancelled, NULL);
-			got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
-			if (error)
-				goto done;
-			if (upa.did_something) {
-				char *id_str;
-				error = got_object_id_str(&id_str, branch_tip);
-				if (error)
-					goto done;
-				printf("Updated to commit %s\n", id_str);
-				free(id_str);
-			} else
-				printf("Already up-to-date\n");
-			print_update_progress_stats(&upa);
-			goto done;
-		}
-		error = got_worktree_merge_write_refs(worktree, branch, repo);
-		if (error)
-			goto done;
-
-		error = got_worktree_merge_branch(worktree, fileindex,
-		    yca_id, branch_tip, repo, update_progress, &upa,
-		    check_cancelled, NULL);
-		if (error)
-			goto done;
-		print_merge_progress_stats(&upa);
-		if (!upa.did_something) {
-			error = got_worktree_merge_abort(worktree, fileindex,
-			    repo, abort_progress, &upa);
-			if (error)
-				goto done;
-			printf("Already up-to-date\n");
-			goto done;
-		}
-	}
-
-	if (interrupt_merge) {
-		error = got_worktree_merge_postpone(worktree, fileindex);
-		if (error)
-			goto done;
-		printf("Merge of %s interrupted on request\n", branch_name);
-	} else if (upa.conflicts > 0 || upa.missing > 0 ||
-	    upa.not_deleted > 0 || upa.unversioned > 0) {
-		error = got_worktree_merge_postpone(worktree, fileindex);
-		if (error)
-			goto done;
-		if (upa.conflicts > 0 && upa.missing == 0 &&
-		    upa.not_deleted == 0 && upa.unversioned == 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before merging "
-			    "can continue");
-		} else if (upa.conflicts > 0) {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "conflicts must be resolved before merging "
-			    "can continue; changes destined for some "
-			    "files were not yet merged and "
-			    "should be merged manually if required before the "
-			    "merge operation is continued");
-		} else {
-			error = got_error_msg(GOT_ERR_CONFLICTS,
-			    "changes destined for some "
-			    "files were not yet merged and should be "
-			    "merged manually if required before the "
-			    "merge operation is continued");
-		}
-		goto done;
-	} else {
-		error = got_worktree_merge_commit(&merge_commit_id, worktree,
-		    fileindex, author, NULL, 1, branch_tip, branch_name,
-		    allow_conflict, repo, continue_merge ? print_status : NULL,
-		    NULL);
-		if (error)
-			goto done;
-		error = got_worktree_merge_complete(worktree, fileindex, repo);
-		if (error)
-			goto done;
-		error = got_object_id_str(&id_str, merge_commit_id);
-		if (error)
-			goto done;
-		printf("Merged %s into %s: %s\n", branch_name,
-		    got_worktree_get_head_ref_name(worktree),
-		    id_str);
-
-	}
-done:
-	free(gitconfig_path);
-	free(id_str);
-	free(merge_commit_id);
-	free(author);
-	free(branch_tip);
-	free(branch_name);
-	free(yca_id);
-	if (branch)
-		got_ref_close(branch);
-	if (wt_branch)
-		got_ref_close(wt_branch);
-	if (worktree)
-		got_worktree_close(worktree);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	return error;
-}
-
-__dead static void
-usage_stage(void)
-{
-	fprintf(stderr, "usage: %s stage [-lpS] [-F response-script] "
-	    "[path ...]\n", getprogname());
-	exit(1);
-}
-
-static const struct got_error *
-print_stage(void *arg, unsigned char status, unsigned char staged_status,
-    const char *path, struct got_object_id *blob_id,
-    struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
-    int dirfd, const char *de_name)
-{
-	const struct got_error *err = NULL;
-	char *id_str = NULL;
-
-	if (staged_status != GOT_STATUS_ADD &&
-	    staged_status != GOT_STATUS_MODIFY &&
-	    staged_status != GOT_STATUS_DELETE)
-		return NULL;
-
-	if (staged_status == GOT_STATUS_ADD ||
-	    staged_status == GOT_STATUS_MODIFY)
-		err = got_object_id_str(&id_str, staged_blob_id);
-	else
-		err = got_object_id_str(&id_str, blob_id);
-	if (err)
-		return err;
-
-	printf("%s %c %s\n", id_str, staged_status, path);
-	free(id_str);
-	return NULL;
-}
-
-static const struct got_error *
-cmd_stage(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_repository *repo = NULL;
-	struct got_worktree *worktree = NULL;
-	char *cwd = NULL;
-	struct got_pathlist_head paths;
-	int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
-	FILE *patch_script_file = NULL;
-	const char *patch_script_path = NULL;
-	struct choose_patch_arg cpa;
-	int *pack_fds = NULL;
-
-	TAILQ_INIT(&paths);
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "F:lpS")) != -1) {
-		switch (ch) {
-		case 'F':
-			patch_script_path = optarg;
-			break;
-		case 'l':
-			list_stage = 1;
-			break;
-		case 'p':
-			pflag = 1;
-			break;
-		case 'S':
-			allow_bad_symlinks = 1;
-			break;
-		default:
-			usage_stage();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (list_stage && (pflag || patch_script_path))
-		errx(1, "-l option cannot be used with other options");
-	if (patch_script_path && !pflag)
-		errx(1, "-F option can only be used together with -p option");
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (error->code == GOT_ERR_NOT_WORKTREE)
-			error = wrap_not_worktree_error(error, "stage", cwd);
-		goto done;
-	}
-
-	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
-	    NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (patch_script_path) {
-		patch_script_file = fopen(patch_script_path, "re");
-		if (patch_script_file == NULL) {
-			error = got_error_from_errno2("fopen",
-			    patch_script_path);
-			goto done;
-		}
-	}
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    got_worktree_get_root_path(worktree));
-	if (error)
-		goto done;
-
-	error = check_merge_in_progress(worktree, repo);
-	if (error)
-		goto done;
-
-	error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
-	if (error)
-		goto done;
-
-	if (list_stage)
-		error = got_worktree_status(worktree, &paths, repo, 0,
-		    print_stage, NULL, check_cancelled, NULL);
-	else {
-		cpa.patch_script_file = patch_script_file;
-		cpa.action = "stage";
-		error = got_worktree_stage(worktree, &paths,
-		    pflag ? NULL : print_status, NULL,
-		    pflag ? choose_patch : NULL, &cpa,
-		    allow_bad_symlinks, repo);
-	}
-done:
-	if (patch_script_file && fclose(patch_script_file) == EOF &&
-	    error == NULL)
-		error = got_error_from_errno2("fclose", patch_script_path);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (worktree)
-		got_worktree_close(worktree);
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
-	free(cwd);
-	return error;
-}
-
-__dead static void
-usage_unstage(void)
-{
-	fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
-	    "[path ...]\n", getprogname());
-	exit(1);
-}
-
-
-static const struct got_error *
-cmd_unstage(int argc, char *argv[])
-{
-	const struct got_error *error = NULL;
-	struct got_repository *repo = NULL;
-	struct got_worktree *worktree = NULL;
-	char *cwd = NULL;
-	struct got_pathlist_head paths;
-	int ch, pflag = 0;
-	struct got_update_progress_arg upa;
-	FILE *patch_script_file = NULL;
-	const char *patch_script_path = NULL;
-	struct choose_patch_arg cpa;
-	int *pack_fds = NULL;
-
-	TAILQ_INIT(&paths);
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
-	    "unveil", NULL) == -1)
-		err(1, "pledge");
-#endif
-
-	while ((ch = getopt(argc, argv, "F:p")) != -1) {
-		switch (ch) {
-		case 'F':
-			patch_script_path = optarg;
-			break;
-		case 'p':
-			pflag = 1;
-			break;
-		default:
-			usage_unstage();
-			/* NOTREACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (patch_script_path && !pflag)
-		errx(1, "-F option can only be used together with -p option");
-
-	cwd = getcwd(NULL, 0);
-	if (cwd == NULL) {
-		error = got_error_from_errno("getcwd");
-		goto done;
-	}
-
-	error = got_repo_pack_fds_open(&pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = got_worktree_open(&worktree, cwd);
-	if (error) {
-		if (error->code == GOT_ERR_NOT_WORKTREE)
-			error = wrap_not_worktree_error(error, "unstage", cwd);
-		goto done;
-	}
-
-	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
-	    NULL, pack_fds);
-	if (error != NULL)
-		goto done;
-
-	if (patch_script_path) {
-		patch_script_file = fopen(patch_script_path, "re");
-		if (patch_script_file == NULL) {
-			error = got_error_from_errno2("fopen",
-			    patch_script_path);
-			goto done;
-		}
-	}
-
-	error = apply_unveil(got_repo_get_path(repo), 0,
-	    got_worktree_get_root_path(worktree));
-	if (error)
-		goto done;
-
-	error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
-	if (error)
-		goto done;
-
-	cpa.patch_script_file = patch_script_file;
-	cpa.action = "unstage";
-	memset(&upa, 0, sizeof(upa));
-	error = got_worktree_unstage(worktree, &paths, update_progress,
-	    &upa, pflag ? choose_patch : NULL, &cpa, repo);
-	if (!error)
-		print_merge_progress_stats(&upa);
-done:
-	if (patch_script_file && fclose(patch_script_file) == EOF &&
-	    error == NULL)
-		error = got_error_from_errno2("fclose", patch_script_path);
-	if (repo) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (worktree)
-		got_worktree_close(worktree);
-	if (pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(pack_fds);
-		if (error == NULL)
-			error = pack_err;
-	}
-	got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
-	free(cwd);
+	if (wanted_ref != NULL && !found)
+		err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref);
+
+done:
+	free(id);
+	free(uuidstr);
+	got_ref_list_free(&refs);
+	got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
+	if (refs_idmap)
+		got_reflist_object_id_map_free(refs_idmap);
+	if (commit)
+		got_object_commit_close(commit);
+	return err;
+}
+
+/*
+ * Create new temp "logmsg" ref of the backed-out or cherrypicked commit
+ * identified by id for log messages to prepopulate the editor on commit.
+ */
+static const struct got_error *
+logmsg_ref(struct got_object_id *id, const char *prefix,
+    struct got_worktree *worktree, struct got_repository *repo)
+{
+	const struct got_error	*err = NULL;
+	char			*idstr, *ref = NULL, *refname = NULL;
+	int			 histedit_in_progress;
+	int			 rebase_in_progress, merge_in_progress;
+
+	/*
+	 * Silenty refuse to create merge reference if any histedit, merge,
+	 * or rebase operation is in progress.
+	 */
+	err = got_worktree_histedit_in_progress(&histedit_in_progress,
+	    worktree);
+	if (err)
+		return err;
+	if (histedit_in_progress)
+		return NULL;
+
+	err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
+	if (err)
+		return err;
+	if (rebase_in_progress)
+		return NULL;
+
+	err = got_worktree_merge_in_progress(&merge_in_progress, worktree,
+	    repo);
+	if (err)
+		return err;
+	if (merge_in_progress)
+		return NULL;
+
+	err = got_object_id_str(&idstr, id);
+	if (err)
+		return err;
+
+	err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix);
+	if (err)
+		goto done;
+
+	if (asprintf(&ref, "%s-%s", refname, idstr) == -1) {
+		err = got_error_from_errno("asprintf");
+		goto done;
+	}
+
+	err = create_ref(ref, got_worktree_get_base_commit_id(worktree),
+	    -1, repo);
+done:
+	free(ref);
+	free(idstr);
+	free(refname);
+	return err;
+}
+
+__dead static void
+usage_cherrypick(void)
+{
+	fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
+	    getprogname());
+	exit(1);
+}
+
+static const struct got_error *
+cmd_cherrypick(int argc, char *argv[])
+{
+	const struct got_error *error = NULL;
+	struct got_worktree *worktree = NULL;
+	struct got_repository *repo = NULL;
+	char *cwd = NULL, *commit_id_str = NULL;
+	struct got_object_id *commit_id = NULL;
+	struct got_commit_object *commit = NULL;
+	struct got_object_qid *pid;
+	int ch, list_refs = 0, remove_refs = 0;
+	struct got_update_progress_arg upa;
+	int *pack_fds = NULL;
+
+#ifndef PROFILE
+	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
+	    "unveil", NULL) == -1)
+		err(1, "pledge");
+#endif
+
+	while ((ch = getopt(argc, argv, "lX")) != -1) {
+		switch (ch) {
+		case 'l':
+			list_refs = 1;
+			break;
+		case 'X':
+			remove_refs = 1;
+			break;
+		default:
+			usage_cherrypick();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (list_refs || remove_refs) {
+		if (argc != 0 && argc != 1)
+			usage_cherrypick();
+	} else if (argc != 1)
+		usage_cherrypick();
+	if (list_refs && remove_refs)
+		option_conflict('l', 'X');
+
+	cwd = getcwd(NULL, 0);
+	if (cwd == NULL) {
+		error = got_error_from_errno("getcwd");
+		goto done;
+	}
+
+	error = got_repo_pack_fds_open(&pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = got_worktree_open(&worktree, cwd);
+	if (error) {
+		if (list_refs || remove_refs) {
+			if (error->code != GOT_ERR_NOT_WORKTREE)
+				goto done;
+		} else {
+			if (error->code == GOT_ERR_NOT_WORKTREE)
+				error = wrap_not_worktree_error(error,
+				    "cherrypick", cwd);
+			goto done;
+		}
+	}
+
+	error = got_repo_open(&repo,
+	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
+	    NULL, pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = apply_unveil(got_repo_get_path(repo), 0,
+	    worktree ? got_worktree_get_root_path(worktree) : NULL);
+	if (error)
+		goto done;
+
+	if (list_refs || remove_refs) {
+		error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
+		    GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN,
+		    argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
+		goto done;
+	}
+
+	error = got_repo_match_object_id(&commit_id, NULL, argv[0],
+	    GOT_OBJ_TYPE_COMMIT, NULL, repo);
+	if (error)
+		goto done;
+	error = got_object_id_str(&commit_id_str, commit_id);
+	if (error)
+		goto done;
+
+	error = got_object_open_as_commit(&commit, repo, commit_id);
+	if (error)
+		goto done;
+	pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
+	memset(&upa, 0, sizeof(upa));
+	error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL,
+	    commit_id, repo, update_progress, &upa, check_cancelled,
+	    NULL);
+	if (error != NULL)
+		goto done;
+
+	if (upa.did_something) {
+		error = logmsg_ref(commit_id,
+		    GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo);
+		if (error)
+			goto done;
+		printf("Merged commit %s\n", commit_id_str);
+	}
+	print_merge_progress_stats(&upa);
+done:
+	free(cwd);
+	if (commit)
+		got_object_commit_close(commit);
+	free(commit_id_str);
+	if (worktree)
+		got_worktree_close(worktree);
+	if (repo) {
+		const struct got_error *close_err = got_repo_close(repo);
+		if (error == NULL)
+			error = close_err;
+	}
+	if (pack_fds) {
+		const struct got_error *pack_err =
+		    got_repo_pack_fds_close(pack_fds);
+		if (error == NULL)
+			error = pack_err;
+	}
+
+	return error;
+}
+
+__dead static void
+usage_backout(void)
+{
+	fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
+	exit(1);
+}
+
+static const struct got_error *
+cmd_backout(int argc, char *argv[])
+{
+	const struct got_error *error = NULL;
+	struct got_worktree *worktree = NULL;
+	struct got_repository *repo = NULL;
+	char *cwd = NULL, *commit_id_str = NULL;
+	struct got_object_id *commit_id = NULL;
+	struct got_commit_object *commit = NULL;
+	struct got_object_qid *pid;
+	int ch, list_refs = 0, remove_refs = 0;
+	struct got_update_progress_arg upa;
+	int *pack_fds = NULL;
+
+#ifndef PROFILE
+	if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
+	    "unveil", NULL) == -1)
+		err(1, "pledge");
+#endif
+
+	while ((ch = getopt(argc, argv, "lX")) != -1) {
+		switch (ch) {
+		case 'l':
+			list_refs = 1;
+			break;
+		case 'X':
+			remove_refs = 1;
+			break;
+		default:
+			usage_backout();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (list_refs || remove_refs) {
+		if (argc != 0 && argc != 1)
+			usage_backout();
+	} else if (argc != 1)
+		usage_backout();
+	if (list_refs && remove_refs)
+		option_conflict('l', 'X');
+
+	cwd = getcwd(NULL, 0);
+	if (cwd == NULL) {
+		error = got_error_from_errno("getcwd");
+		goto done;
+	}
+
+	error = got_repo_pack_fds_open(&pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = got_worktree_open(&worktree, cwd);
+	if (error) {
+		if (list_refs || remove_refs) {
+			if (error->code != GOT_ERR_NOT_WORKTREE)
+				goto done;
+		} else {
+			if (error->code == GOT_ERR_NOT_WORKTREE)
+				error = wrap_not_worktree_error(error,
+				    "backout", cwd);
+			goto done;
+		}
+	}
+
+	error = got_repo_open(&repo,
+	    worktree ? got_worktree_get_repo_path(worktree) : cwd,
+	    NULL, pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = apply_unveil(got_repo_get_path(repo), 0,
+	    worktree ? got_worktree_get_root_path(worktree) : NULL);
+	if (error)
+		goto done;
+
+	if (list_refs || remove_refs) {
+		error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX,
+		    GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN,
+		    argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
+		goto done;
+	}
+
+	error = got_repo_match_object_id(&commit_id, NULL, argv[0],
+	    GOT_OBJ_TYPE_COMMIT, NULL, repo);
+	if (error)
+		goto done;
+	error = got_object_id_str(&commit_id_str, commit_id);
+	if (error)
+		goto done;
+
+	error = got_object_open_as_commit(&commit, repo, commit_id);
+	if (error)
+		goto done;
+	pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
+	if (pid == NULL) {
+		error = got_error(GOT_ERR_ROOT_COMMIT);
+		goto done;
+	}
+
+	memset(&upa, 0, sizeof(upa));
+	error = got_worktree_merge_files(worktree, commit_id, &pid->id,
+	    repo, update_progress, &upa, check_cancelled, NULL);
+	if (error != NULL)
+		goto done;
+
+	if (upa.did_something) {
+		error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX,
+		    worktree, repo);
+		if (error)
+			goto done;
+		printf("Backed out commit %s\n", commit_id_str);
+	}
+	print_merge_progress_stats(&upa);
+done:
+	free(cwd);
+	if (commit)
+		got_object_commit_close(commit);
+	free(commit_id_str);
+	if (worktree)
+		got_worktree_close(worktree);
+	if (repo) {
+		const struct got_error *close_err = got_repo_close(repo);
+		if (error == NULL)
+			error = close_err;
+	}
+	if (pack_fds) {
+		const struct got_error *pack_err =
+		    got_repo_pack_fds_close(pack_fds);
+		if (error == NULL)
+			error = pack_err;
+	}
 	return error;
 }