commit f4ab0e5770b96257cb1a43cfe292daa54f2b402e from: Stefan Sperling date: Thu Mar 28 14:35:03 2024 UTC 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 state. ok op@ commit - a397e3fbad25f5da2f4a33e1d2ac8248f32aa24b commit + f4ab0e5770b96257cb1a43cfe292daa54f2b402e blob - 8443d267c1f9a1e49d05b5258a78b6f9e247ae00 blob + 27fee027d191881e30323c0d8436d8803ffe5eca --- got/got.1 +++ got/got.1 @@ -822,6 +822,12 @@ Changes created on top of staged changes are indicated .It MM Ta file was modified after earlier changes have been staged .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 blob - 3c8cb0c12d7936fbec44d19b84f4631da483f0dc blob + 4486b08390756e709d18c25cbfc370d75101ecc2 --- got/got.c +++ got/got.c @@ -6420,6 +6420,56 @@ print_status(void *arg, unsigned char status, unsigned } print: printf("%c%c %s\n", status, staged_status, path); + return NULL; +} + +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; } @@ -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 @@ -7009,6 +7009,70 @@ got_worktree_rebase_in_progress(int *in_progress, stru *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0); free(tmp_branch_name); 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 * @@ -8033,7 +8097,48 @@ done: *fileindex = NULL; } lock_worktree(worktree, LOCK_EX); + } + 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; } @@ -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 <