Re: [PATCH v2] git-prompt: show presence of unresolved conflicts at command prompt
- From
Justin Donnelly <justinrdonnelly@gmail.com>
- Date
- Aug 14, 2022, 21:06 UTC
- Message-ID
- <CAGTqyRw-SYDbQy9aktq5s3ZhoDhUOCf-pEopjH9m7v5+PH7Qqg@mail.gmail.com>
- In-Reply-To
- <pull.1302.v2.git.1659132518935.gitgitgadget@gmail.com>
On Fri, Jul 29, 2022 at 6:08 PM Justin Donnelly via GitGitGadget <gitgitgadget@gmail.com> wrote:
Show 368 quoted lines
>
> From: Justin Donnelly <justinrdonnelly@gmail.com>
>
> If GIT_PS1_SHOWCONFLICTSTATE is set to "yes", show the word "CONFLICT"
> on the command prompt when there are unresolved conflicts.
>
> Example prompt: (main|CONFLICT)
>
> Signed-off-by: Justin Donnelly <justinrdonnelly@gmail.com>
> ---
> Show 'CONFLICT' indicator at command prompt
>
> This patch adds functionality for bash/zsh to show "CONFLICT" on the
> prompt in cases where there are unresolved conflicts. The feature is
> only enabled after setting an environment variable.
>
> The conflict state is determined by running git ls-files --unmerged. In
> my testing, the performance was very good. It took around 0.01 seconds
> to run git ls-files --unmerged regardless of the number of conflicts, or
> their depth, even on very large projects (Linux kernel). However, if
> anybody has any concerns with this, I'm open to other options.
>
> Any tests that were impacted (with the conflict prompt feature enabled)
> were duplicated. The original test was left as-is (no changes, and
> conflict prompt feature disabled). The new version of each test enables
> the conflict prompt feature and confirms the prompt includes
> "|CONFLICT".
>
> ------------------------------------------------------------------------
>
> Changes since v1:
>
> * This feature is now disabled by default.
> * Created new tests for conflict state (instead of modifying existing
> tests).
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1302%2Fjustinrdonnelly%2Fconflict-indicator-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1302/justinrdonnelly/conflict-indicator-v2
> Pull-Request: https://github.com/gitgitgadget/git/pull/1302
>
> Range-diff vs v1:
>
> 1: e380826dcaf ! 1: 7154d695426 git-prompt: show 'CONFLICT' indicator at command prompt
> @@ Metadata
> Author: Justin Donnelly <justinrdonnelly@gmail.com>
>
> ## Commit message ##
> - git-prompt: show 'CONFLICT' indicator at command prompt
> + git-prompt: show presence of unresolved conflicts at command prompt
>
> - When there are unresolved conflicts, show the word 'CONFLICT' on the
> - command prompt. Similar to other state indicators, this provides
> - information to the user about the current state of the repository.
> + If GIT_PS1_SHOWCONFLICTSTATE is set to "yes", show the word "CONFLICT"
> + on the command prompt when there are unresolved conflicts.
>
> Example prompt: (main|CONFLICT)
>
> @@ contrib/completion/git-prompt.sh
> # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
> # by setting GIT_PS1_OMITSPARSESTATE.
> #
> -+# When there is a conflict, the prompt will include "|CONFLICT". This can
> -+# be omitted by setting GIT_PS1_OMITCONFLICTSTATE.
> ++# If you would like to see a notification on the prompt when there are
> ++# unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The
> ++# prompt will include "|CONFLICT".
> +#
> # If you would like to see more information about the identity of
> # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
> @@ contrib/completion/git-prompt.sh: __git_ps1 ()
> fi
>
> + local conflict="" # state indicator for unresolved conflicts
> -+ if [[ -z "${GIT_PS1_OMITCONFLICTSTATE-}" ]] &&
> ++ if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] &&
> + [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
> + conflict="|CONFLICT"
> + fi
> @@ contrib/completion/git-prompt.sh: __git_ps1 ()
> if [ "${__git_printf_supports_v-}" != yes ]; then
>
> ## t/t9903-bash-prompt.sh ##
> -@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - interactive rebase' '
> - '
> -
> - test_expect_success 'prompt - rebase merge' '
> -- printf " (b2|REBASE 1/3)" >expected &&
> -+ printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> - git checkout b2 &&
> +@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - rebase merge' '
> test_when_finished "git checkout main" &&
> test_must_fail git rebase --merge b1 b2 &&
> -@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - rebase merge' '
> + test_when_finished "git rebase --abort" &&
> +- __git_ps1 >"$actual" &&
> ++ (
> ++ sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> ++ test_cmp expected "$actual"
> ++'
> ++
> ++test_expect_success 'prompt - rebase merge conflict' '
> ++ printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> ++ git checkout b2 &&
> ++ test_when_finished "git checkout main" &&
> ++ test_must_fail git rebase --merge b1 b2 &&
> ++ test_when_finished "git rebase --abort" &&
> ++ (
> ++ GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> + test_cmp expected "$actual"
> '
>
> - test_expect_success 'prompt - rebase am' '
> -- printf " (b2|REBASE 1/3)" >expected &&
> -+ printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> - git checkout b2 &&
> +@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - rebase am' '
> test_when_finished "git checkout main" &&
> test_must_fail git rebase --apply b1 b2 &&
> -@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - rebase am' '
> + test_when_finished "git rebase --abort" &&
> +- __git_ps1 >"$actual" &&
> ++ (
> ++ sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> ++ test_cmp expected "$actual"
> ++'
> ++
> ++test_expect_success 'prompt - rebase am conflict' '
> ++ printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> ++ git checkout b2 &&
> ++ test_when_finished "git checkout main" &&
> ++ test_must_fail git rebase --apply b1 b2 &&
> ++ test_when_finished "git rebase --abort" &&
> ++ (
> ++ GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> + test_cmp expected "$actual"
> '
>
> - test_expect_success 'prompt - merge' '
> -- printf " (b1|MERGING)" >expected &&
> -+ printf " (b1|MERGING|CONFLICT)" >expected &&
> - git checkout b1 &&
> +@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - merge' '
> test_when_finished "git checkout main" &&
> test_must_fail git merge b2 &&
> -@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - merge' '
> + test_when_finished "git reset --hard" &&
> +- __git_ps1 >"$actual" &&
> ++ (
> ++ sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> ++ test_cmp expected "$actual"
> ++'
> ++
> ++test_expect_success 'prompt - merge conflict' '
> ++ printf " (b1|MERGING|CONFLICT)" >expected &&
> ++ git checkout b1 &&
> ++ test_when_finished "git checkout main" &&
> ++ test_must_fail git merge b2 &&
> ++ test_when_finished "git reset --hard" &&
> ++ (
> ++ GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> + test_cmp expected "$actual"
> '
>
> - test_expect_success 'prompt - cherry-pick' '
> -- printf " (main|CHERRY-PICKING)" >expected &&
> -+ printf " (main|CHERRY-PICKING|CONFLICT)" >expected &&
> +@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - cherry-pick' '
> + printf " (main|CHERRY-PICKING)" >expected &&
> test_must_fail git cherry-pick b1 b1^ &&
> test_when_finished "git cherry-pick --abort" &&
> - __git_ps1 >"$actual" &&
> +- __git_ps1 >"$actual" &&
> ++ (
> ++ sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> test_cmp expected "$actual" &&
> -+ printf " (main|CHERRY-PICKING)" >expected &&
> git reset --merge &&
> test_must_fail git rev-parse CHERRY_PICK_HEAD &&
> - __git_ps1 >"$actual" &&
> +@@ t/t9903-bash-prompt.sh: test_expect_success 'prompt - cherry-pick' '
> + test_cmp expected "$actual"
> + '
> +
> ++test_expect_success 'prompt - cherry-pick conflict' '
> ++ printf " (main|CHERRY-PICKING|CONFLICT)" >expected &&
> ++ test_must_fail git cherry-pick b1 b1^ &&
> ++ test_when_finished "git cherry-pick --abort" &&
> ++ (
> ++ GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> ++ __git_ps1 >"$actual"
> ++ ) &&
> ++ test_cmp expected "$actual"
> ++'
> ++
> + test_expect_success 'prompt - revert' '
> + printf " (main|REVERTING)" >expected &&
> + test_must_fail git revert b1^ b1 &&
>
>
> contrib/completion/git-prompt.sh | 12 +++++-
> t/t9903-bash-prompt.sh | 70 ++++++++++++++++++++++++++++++--
> 2 files changed, 77 insertions(+), 5 deletions(-)
>
> diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
> index 1435548e004..57972c2845c 100644
> --- a/contrib/completion/git-prompt.sh
> +++ b/contrib/completion/git-prompt.sh
> @@ -84,6 +84,10 @@
> # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
> # by setting GIT_PS1_OMITSPARSESTATE.
> #
> +# If you would like to see a notification on the prompt when there are
> +# unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The
> +# prompt will include "|CONFLICT".
> +#
> # If you would like to see more information about the identity of
> # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
> # to one of these values:
> @@ -508,6 +512,12 @@ __git_ps1 ()
> r="$r $step/$total"
> fi
>
> + local conflict="" # state indicator for unresolved conflicts
> + if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] &&
> + [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
> + conflict="|CONFLICT"
> + fi
> +
> local w=""
> local i=""
> local s=""
> @@ -572,7 +582,7 @@ __git_ps1 ()
> fi
>
> local f="$h$w$i$s$u$p"
> - local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}"
> + local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
>
> if [ $pcmode = yes ]; then
> if [ "${__git_printf_supports_v-}" != yes ]; then
> diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
> index 6a30f5719c3..47eb98893ef 100755
> --- a/t/t9903-bash-prompt.sh
> +++ b/t/t9903-bash-prompt.sh
> @@ -188,7 +188,23 @@ test_expect_success 'prompt - rebase merge' '
> test_when_finished "git checkout main" &&
> test_must_fail git rebase --merge b1 b2 &&
> test_when_finished "git rebase --abort" &&
> - __git_ps1 >"$actual" &&
> + (
> + sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> + __git_ps1 >"$actual"
> + ) &&
> + test_cmp expected "$actual"
> +'
> +
> +test_expect_success 'prompt - rebase merge conflict' '
> + printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> + git checkout b2 &&
> + test_when_finished "git checkout main" &&
> + test_must_fail git rebase --merge b1 b2 &&
> + test_when_finished "git rebase --abort" &&
> + (
> + GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> + __git_ps1 >"$actual"
> + ) &&
> test_cmp expected "$actual"
> '
>
> @@ -198,7 +214,23 @@ test_expect_success 'prompt - rebase am' '
> test_when_finished "git checkout main" &&
> test_must_fail git rebase --apply b1 b2 &&
> test_when_finished "git rebase --abort" &&
> - __git_ps1 >"$actual" &&
> + (
> + sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> + __git_ps1 >"$actual"
> + ) &&
> + test_cmp expected "$actual"
> +'
> +
> +test_expect_success 'prompt - rebase am conflict' '
> + printf " (b2|REBASE 1/3|CONFLICT)" >expected &&
> + git checkout b2 &&
> + test_when_finished "git checkout main" &&
> + test_must_fail git rebase --apply b1 b2 &&
> + test_when_finished "git rebase --abort" &&
> + (
> + GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> + __git_ps1 >"$actual"
> + ) &&
> test_cmp expected "$actual"
> '
>
> @@ -208,7 +240,23 @@ test_expect_success 'prompt - merge' '
> test_when_finished "git checkout main" &&
> test_must_fail git merge b2 &&
> test_when_finished "git reset --hard" &&
> - __git_ps1 >"$actual" &&
> + (
> + sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> + __git_ps1 >"$actual"
> + ) &&
> + test_cmp expected "$actual"
> +'
> +
> +test_expect_success 'prompt - merge conflict' '
> + printf " (b1|MERGING|CONFLICT)" >expected &&
> + git checkout b1 &&
> + test_when_finished "git checkout main" &&
> + test_must_fail git merge b2 &&
> + test_when_finished "git reset --hard" &&
> + (
> + GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> + __git_ps1 >"$actual"
> + ) &&
> test_cmp expected "$actual"
> '
>
> @@ -216,7 +264,10 @@ test_expect_success 'prompt - cherry-pick' '
> printf " (main|CHERRY-PICKING)" >expected &&
> test_must_fail git cherry-pick b1 b1^ &&
> test_when_finished "git cherry-pick --abort" &&
> - __git_ps1 >"$actual" &&
> + (
> + sane_unset GIT_PS1_SHOWCONFLICTSTATE &&
> + __git_ps1 >"$actual"
> + ) &&
> test_cmp expected "$actual" &&
> git reset --merge &&
> test_must_fail git rev-parse CHERRY_PICK_HEAD &&
> @@ -224,6 +275,17 @@ test_expect_success 'prompt - cherry-pick' '
> test_cmp expected "$actual"
> '
>
> +test_expect_success 'prompt - cherry-pick conflict' '
> + printf " (main|CHERRY-PICKING|CONFLICT)" >expected &&
> + test_must_fail git cherry-pick b1 b1^ &&
> + test_when_finished "git cherry-pick --abort" &&
> + (
> + GIT_PS1_SHOWCONFLICTSTATE="yes" &&
> + __git_ps1 >"$actual"
> + ) &&
> + test_cmp expected "$actual"
> +'
> +
> test_expect_success 'prompt - revert' '
> printf " (main|REVERTING)" >expected &&
> test_must_fail git revert b1^ b1 &&
>
> base-commit: 6a475b71f8c4ce708d69fdc9317aefbde3769e25
> --
> gitgitgadget[SubmittingPatches](https://github.com/git/git/blob/master/Documentation/SubmittingPatches) recommends using `git-contacts` to determine who to "cc" on the email. I used GitGitGadget, which doesn't cc anybody by default (I see now that others manually add cc's to the PR description). So I've added the following cc's to this email: Ævar Arnfjörð Bjarmason Junio C Hamano Elijah Newren Phillip Wood Johannes Schindelin
I hope this is against protocol/etiquette, but after some initial feedback from Junio, I haven't gotten any more. I wasn't sure if nobody had seen the patch, or if there just wasn't any interest.
Thanks, Justin