From: Stefan Sperling Subject: make got status show interrupted operations To: gameoftrees@openbsd.org Date: Thu, 28 Mar 2024 14:59:07 +0100 This small UI tweak makes it easier to users to identify whether a work tree is currently in an interrupted operation. ok? ----------------------------------------------- make 'got status' display interrupted rebase, histedit, and merge operations When an operation is interrupted add a trailing message to status output which displays the operation and branches involved. This information will be useful when diagnosing problem reports and it helps new users with contextualizing multi-operation work tree states. diff a854b8c994a1381e4c6f2ba45bef9c22da0ec956 96a6a00dbe4a094394ebc2d7c77082c01c9850e1 commit - a854b8c994a1381e4c6f2ba45bef9c22da0ec956 commit + 96a6a00dbe4a094394ebc2d7c77082c01c9850e1 blob - ee41732e49ededaf4c54218c0d0b9deb2c1feff9 blob + 24c38ee62b98e9ab39fdf9d2f67d3b4b3502a98c --- got/got.1 +++ got/got.1 @@ -823,6 +823,12 @@ Changes created on top of staged changes are indicated .It MA Ta file was modified after having been staged for addition .El .Pp +If the work tree contains the results of an interrupted +.Cm got rebase , +.Cm got histedit, or +.Cm got merge +operation then display a message which shows the branches involved. +.Pp The options for .Cm got status are as follows: blob - 5775865ce9bc5a0a9f5d8638ed832cf4ef970d67 blob + f7503f5f1f6ae825fc05d3dfc22e2c43d67b1afd --- got/got.c +++ got/got.c @@ -6424,6 +6424,56 @@ print: } static const struct got_error * +show_operation_in_progress(struct got_worktree *worktree, + struct got_repository *repo) +{ + const struct got_error *err; + char *new_base_branch_name = NULL; + char *branch_name = NULL; + int rebase_in_progress, histedit_in_progress, merge_in_progress; + + err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); + if (err) + return err; + if (rebase_in_progress) { + err = got_worktree_rebase_info(&new_base_branch_name, + &branch_name, worktree, repo); + if (err) + return err; + printf("Work tree is rebasing %s onto %s\n", + branch_name, new_base_branch_name); + } + + err = got_worktree_histedit_in_progress(&histedit_in_progress, + worktree); + if (err) + return err; + if (histedit_in_progress) { + err = got_worktree_histedit_info(&branch_name, worktree, repo); + if (err) + return err; + printf("Work tree is editing the history of %s\n", branch_name); + } + + err = got_worktree_merge_in_progress(&merge_in_progress, + worktree, repo); + if (err) + return err; + if (merge_in_progress) { + err = got_worktree_merge_info(&branch_name, worktree, + repo); + if (err) + return err; + printf("Work tree is merging %s into %s\n", branch_name, + got_worktree_get_head_ref_name(worktree)); + } + + free(new_base_branch_name); + free(branch_name); + return NULL; +} + +static const struct got_error * cmd_status(int argc, char *argv[]) { const struct got_error *close_err, *error = NULL; @@ -6522,6 +6572,10 @@ cmd_status(int argc, char *argv[]) error = got_worktree_status(worktree, &paths, repo, no_ignores, print_status, &st, check_cancelled, NULL); + if (error) + goto done; + + error = show_operation_in_progress(worktree, repo); done: if (pack_fds) { const struct got_error *pack_err = blob - e45d7096cd1e609bd13f07ec1c9dcfcaf5a6b508 blob + d2b62724acbc48c141e49a60bd36765fe2c58cad --- include/got_worktree.h +++ include/got_worktree.h @@ -319,6 +319,9 @@ const struct got_error *got_worktree_rebase_continue(s /* Check whether a, potentially interrupted, rebase operation is in progress. */ const struct got_error *got_worktree_rebase_in_progress(int *, struct got_worktree *); +/* Return information about an in-progress rebase operation. */ +const struct got_error *got_worktree_rebase_info(char **new_base_branch_name, + char **branch_name, struct got_worktree *, struct got_repository *); /* * Merge changes from the commit currently being rebased into the work tree. @@ -391,6 +394,10 @@ const struct got_error *got_worktree_histedit_continue /* Check whether a histedit operation is in progress. */ const struct got_error *got_worktree_histedit_in_progress(int *, struct got_worktree *); +/* Return information about an in-progress histedit operation. */ +const struct got_error *got_worktree_histedit_info( + char **branch_nane, struct got_worktree *, + struct got_repository *); /* * Merge changes from the commit currently being edited into the work tree. @@ -507,6 +514,10 @@ const struct got_error *got_worktree_merge_complete( /* Check whether a merge operation is in progress. */ const struct got_error *got_worktree_merge_in_progress(int *, struct got_worktree *, struct got_repository *); +/* Return information about an in-progress merge operation. */ +const struct got_error * +got_worktree_merge_info(char **branch_name, struct got_worktree *, + struct got_repository *); /* * Prepare for merging a branch into the work tree's current branch: lock the blob - f3dd65c0798d2e84fb8a2d174be5c350115e06a1 blob + 860d8c6d46a8db026e455591d706160d86c7f3fe --- lib/worktree.c +++ lib/worktree.c @@ -7011,6 +7011,70 @@ got_worktree_rebase_in_progress(int *in_progress, stru return NULL; } +const struct got_error * +got_worktree_rebase_info(char **new_base_branch_name, char **branch_name, + struct got_worktree *worktree, struct got_repository *repo) +{ + const struct got_error *err; + char *new_base_branch_ref_name = NULL; + char *branch_ref_name = NULL; + struct got_reference *branch_ref = NULL, *branch = NULL; + struct got_reference *new_base_branch = NULL; + + *new_base_branch_name = NULL; + *branch_name = NULL; + + err = get_rebase_branch_symref_name(&branch_ref_name, worktree); + if (err) + goto done; + + err = get_newbase_symref_name(&new_base_branch_ref_name, worktree); + if (err) + goto done; + + err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); + if (err) + goto done; + + err = got_ref_open(&branch, repo, + got_ref_get_symref_target(branch_ref), 0); + if (err) + goto done; + + err = got_ref_open(&new_base_branch, repo, + new_base_branch_ref_name, 0); + if (err) + goto done; + + if (!got_ref_is_symbolic(new_base_branch)) { + err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, + "%s is not a symbolic reference", + got_ref_get_name(branch_ref)); + goto done; + } + + *new_base_branch_name = strdup(got_ref_get_symref_target( + new_base_branch)); + if (*new_base_branch_name == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + *branch_name = strdup(got_ref_get_name(branch)); + if (*branch_name == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } +done: + free(branch_ref_name); + if (branch_ref) + got_ref_close(branch_ref); + if (new_base_branch) + got_ref_close(new_base_branch); + if (branch) + got_ref_close(branch); + return err; +} + static const struct got_error * collect_rebase_commit_msg(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) @@ -8037,6 +8101,47 @@ done: return err; } +const struct got_error * +got_worktree_histedit_info(char **branch_name, + struct got_worktree *worktree, struct got_repository *repo) +{ + const struct got_error *err; + struct got_reference *branch_ref = NULL; + char *branch_ref_name = NULL; + + *branch_name = NULL; + + err = get_histedit_branch_symref_name(&branch_ref_name, worktree); + if (err) + goto done; + + err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); + if (err) + goto done; + + if (!got_ref_is_symbolic(branch_ref)) { + err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, + "%s is not a symbolic reference", + got_ref_get_name(branch_ref)); + goto done; + } + + *branch_name = strdup(got_ref_get_symref_target(branch_ref)); + if (*branch_name == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } +done: + free(branch_ref_name); + if (branch_ref) + got_ref_close(branch_ref); + if (err) { + free(*branch_name); + *branch_name = NULL; + } + return err; +} + static const struct got_error * delete_histedit_refs(struct got_worktree *worktree, struct got_repository *repo) { @@ -8861,6 +8966,49 @@ done: } const struct got_error * +got_worktree_merge_info(char **branch_name, struct got_worktree *worktree, + struct got_repository *repo) +{ + const struct got_error *err; + char *branch_refname = NULL; + struct got_reference *branch_ref = NULL; + + *branch_name = NULL; + + err = get_merge_branch_ref_name(&branch_refname, worktree); + if (err) + goto done; + + err = got_ref_open(&branch_ref, repo, branch_refname, 0); + if (err) + goto done; + + if (!got_ref_is_symbolic(branch_ref)) { + err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, + "%s is not a symbolic reference", + got_ref_get_name(branch_ref)); + goto done; + } + *branch_name = strdup(got_ref_get_symref_target(branch_ref)); + if (*branch_name == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + +done: + free(branch_refname); + if (branch_ref) + got_ref_close(branch_ref); + if (err) { + if (*branch_name) { + free(*branch_name); + *branch_name = NULL; + } + } + return err; +} + +const struct got_error * got_worktree_merge_abort(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) blob - 4540f35d9804387c36072d1da2829b2c460a5171 blob + 13dd31e4feec963e558e3e0eebbcfac22c15c741 --- regress/cmdline/histedit.sh +++ regress/cmdline/histedit.sh @@ -1186,7 +1186,10 @@ test_histedit_path_prefix_edit() { (cd $testroot/wt && got status > $testroot/stdout) - echo "M zeta"> $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected - echo "D beta" >> $testroot/stdout.expected - echo "A epsilon/new" >> $testroot/stdout.expected - echo "M gamma/delta" >> $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "A added-file" > $testroot/stdout.expected - echo "C alpha" >> $testroot/stdout.expected - echo "D beta" >> $testroot/stdout.expected - echo "A epsilon/new" >> $testroot/stdout.expected - echo "M gamma/delta" >> $testroot/stdout.expected - echo "A symlink" >> $testroot/stdout.expected - echo "? unversioned-file" >> $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "M gamma/delta" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "M alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "A added-file" > $testroot/stdout.expected - echo "C alpha" >> $testroot/stdout.expected - echo "A epsilon/new" >> $testroot/stdout.expected - echo "? unversioned-file" >> $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected < $testroot/stdout) - echo "C alpha" > $testroot/stdout.expected + cat > $testroot/stdout.expected <