Skip to content

Commit aa0644f

Browse files
szedergitster
authored andcommitted
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs that will fetch to a local branch with the same name as in the remote repository, e.g. 'master:master'. This also completes non-fast-forward refspecs, i.e. after a '+' prefix like '+master:master', and fully qualified refspecs, e.g. 'refs/heads/master:refs/heads/master'. However, it does not complete non-fast-forward fully qualified refspecs (or fully qualified refspecs following any other prefix, e.g. '--option=', though currently no git command supports such an option, but third party git commands might). These refspecs are listed by the __git_refs2() function, which is just a thin wrapper iterating over __git_refs()'s output, turning each listed ref into a refspec. Now, it's certainly possible to modify __git_refs2() and its callsite to pass an extra parameter containing only the ref part of the current word to be completed (to follow suit of the previous commit) to deal with prefixed fully qualified refspecs as well. Unfortunately, keeping the current behavior unchanged in the "no extra parameter" case brings in a bit of subtlety, which makes the resulting code ugly and compelled me to write a 8-line long comment in the proof of concept. Not good. However, since the callsite has to be modified for proper functioning anyway, we might as well leave __git_refs2() as is and introduce a new helper function without backwards compatibility concerns. Add the new function __git_complete_fetch_refspecs() that has all the necessary parameters to do the right thing in all cases mentioned above, including non-fast-forward fully qualified refspecs. This new function can also easier benefit from optimizations coming later in this patch series. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 2ea328a commit aa0644f

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

contrib/completion/git-completion.bash

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ __git_complete_refs ()
486486
}
487487

488488
# __git_refs2 requires 1 argument (to pass to __git_refs)
489+
# Deprecated: use __git_complete_fetch_refspecs() instead.
489490
__git_refs2 ()
490491
{
491492
local i
@@ -494,6 +495,24 @@ __git_refs2 ()
494495
done
495496
}
496497

498+
# Completes refspecs for fetching from a remote repository.
499+
# 1: The remote repository.
500+
# 2: A prefix to be added to each listed refspec (optional).
501+
# 3: The ref to be completed as a refspec instead of the current word to be
502+
# completed (optional)
503+
# 4: A suffix to be appended to each listed refspec instead of the default
504+
# space (optional).
505+
__git_complete_fetch_refspecs ()
506+
{
507+
local i remote="$1" pfx="${2-}" cur_="${3-$cur}" sfx="${4- }"
508+
509+
__gitcomp_nl "$(
510+
for i in $(__git_refs "$remote" "" "" "$cur_") ; do
511+
echo "$i:$i"
512+
done
513+
)" "$pfx" "$cur_" "$sfx"
514+
}
515+
497516
# __git_refs_remotes requires 1 argument (to pass to ls-remote)
498517
__git_refs_remotes ()
499518
{
@@ -686,7 +705,7 @@ __git_complete_remote_or_refspec ()
686705
case "$cmd" in
687706
fetch)
688707
if [ $lhs = 1 ]; then
689-
__gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_"
708+
__git_complete_fetch_refspecs "$remote" "$pfx" "$cur_"
690709
else
691710
__git_complete_refs --pfx="$pfx" --cur="$cur_"
692711
fi

t/t9902-completion.sh

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,74 @@ test_expect_success '__git_complete_refs - suffix' '
912912
test_cmp expected out
913913
'
914914

915+
test_expect_success '__git_complete_fetch_refspecs - simple' '
916+
sed -e "s/Z$//" >expected <<-EOF &&
917+
HEAD:HEAD Z
918+
branch-in-other:branch-in-other Z
919+
master-in-other:master-in-other Z
920+
EOF
921+
(
922+
cur= &&
923+
__git_complete_fetch_refspecs other &&
924+
print_comp
925+
) &&
926+
test_cmp expected out
927+
'
928+
929+
test_expect_success '__git_complete_fetch_refspecs - matching' '
930+
sed -e "s/Z$//" >expected <<-EOF &&
931+
branch-in-other:branch-in-other Z
932+
EOF
933+
(
934+
cur=br &&
935+
__git_complete_fetch_refspecs other "" br &&
936+
print_comp
937+
) &&
938+
test_cmp expected out
939+
'
940+
941+
test_expect_success '__git_complete_fetch_refspecs - prefix' '
942+
sed -e "s/Z$//" >expected <<-EOF &&
943+
+HEAD:HEAD Z
944+
+branch-in-other:branch-in-other Z
945+
+master-in-other:master-in-other Z
946+
EOF
947+
(
948+
cur="+" &&
949+
__git_complete_fetch_refspecs other "+" "" &&
950+
print_comp
951+
) &&
952+
test_cmp expected out
953+
'
954+
955+
test_expect_success '__git_complete_fetch_refspecs - fully qualified' '
956+
sed -e "s/Z$//" >expected <<-EOF &&
957+
refs/heads/branch-in-other:refs/heads/branch-in-other Z
958+
refs/heads/master-in-other:refs/heads/master-in-other Z
959+
refs/tags/tag-in-other:refs/tags/tag-in-other Z
960+
EOF
961+
(
962+
cur=refs/ &&
963+
__git_complete_fetch_refspecs other "" refs/ &&
964+
print_comp
965+
) &&
966+
test_cmp expected out
967+
'
968+
969+
test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' '
970+
sed -e "s/Z$//" >expected <<-EOF &&
971+
+refs/heads/branch-in-other:refs/heads/branch-in-other Z
972+
+refs/heads/master-in-other:refs/heads/master-in-other Z
973+
+refs/tags/tag-in-other:refs/tags/tag-in-other Z
974+
EOF
975+
(
976+
cur=+refs/ &&
977+
__git_complete_fetch_refspecs other + refs/ &&
978+
print_comp
979+
) &&
980+
test_cmp expected out
981+
'
982+
915983
test_expect_success 'teardown after ref completion' '
916984
git branch -d matching-branch &&
917985
git tag -d matching-tag &&

0 commit comments

Comments
 (0)