11

I am using zsh with oh-my-zsh on Ubuntu 18.04.2. Currently, Git is installed at version 2.20.1.

Whenever I want to checkout a local branch from a remote (origin) I try to use the tab completion in the shell as follows:

git checkout fea<TAB>

The tab completion results in:

git checkout origin/feature

What I actually expect from the tab completion is:

git checkout feature

How can I configure the tab completion to correctly (?) complete the remote branch - or am I missing something? My dotfiles are public.


Reply to the comment from Tarun Lalwani: The output of git branch -a is:

develop
* housekeeping
remotes/origin/HEAD -> origin/develop
remotes/origin/develop
remotes/origin/master
remotes/origin/release
remotes/origin/feature

JJD
  • 44,755
  • 49
  • 183
  • 309
  • 1
    `git checkout origin feature` is not even a correct command? The correct command is `git checkout feature` so if you tab there I believe it should work fine – Tarun Lalwani Jun 27 '19 at 18:43
  • Thank you for pointing out this error. I changed the question earlier and made a mistake there. I fixed that now. – JJD Jun 27 '19 at 19:59
  • 2
    can you add the output of `git branch -a` as well to your question? – Tarun Lalwani Jun 28 '19 at 03:31
  • I use Fedora 25 (rather old, we're currently under #30) and have almost never used zsh, but I just installed the whole suit just to make the test and it appears to work as you expect it to do. So maybe upgrading the suit directly from the source ( https://github.com/robbyrussell/oh-my-zsh#basic-installation ) might do the trick. Otherwise, you may want to take a look at `~/.oh-my-zsh/plugins/git/git.plugin.zsh`. – Obsidian Jun 30 '19 at 19:39
  • @TarunLalwani I added the output to my question. – JJD Jul 04 '19 at 09:30

2 Answers2

3

After thorough research, it turns out that completion of git checkout under ZSH is not fulfilled by oh-my-zsh, but from the _git function provided with the shell facilities.

As stated in the comments, I couldn't reproduce the issue you experienced. Everything seems to work as expected. Nevertheless…

Check out the following file:

/usr/share/zsh/<5.x>/functions/_git

My local zsh version is 5.2. Around row 450, you can see:

  case $state in
    (branch-or-tree-ish-or-file)
      # TODO: Something about *:: brings us here when we complete at "-".  I
      # guess that this makes sense in a way, as we might want to treat it as
      # an argument, but I can't find anything in the documentation about this
      # behavior.
      [[ $line[CURRENT] = -* ]] && return
      if (( CURRENT == 1 )) && [[ -z $opt_args[(I)--] ]]; then
        # TODO: Allow A...B
        local branch_arg='' \
              remote_branch_noprefix_arg='remote branches::__git_remote_branch_names_noprefix' \
              tree_ish_arg='tree-ishs::__git_tree_ishs' \
              file_arg='modified-files::__git_modified_files'

        if [[ -n ${opt_args[(I)-b|-B|--orphan|--detach]} ]]; then
          remote_branch_noprefix_arg=
          file_arg=
        elif [[ -n $opt_args[(I)--track] ]]; then
          branch_arg='remote-branches::__git_remote_branch_names'
          remote_branch_noprefix_arg=
          tree_ish_arg=
          file_arg=
        elif [[ -n ${opt_args[(I)--ours|--theirs|-m|--conflict|--patch]} ]]; then
          remote_branch_noprefix_arg=
        fi

        _alternative \
          $branch_arg \
          $remote_branch_noprefix_arg \
          $tree_ish_arg \
          $file_arg && ret=0

Removing one of the arrays passed to _alternative changes what's suggested to you when completing a branch name after git checkout. In particular, removing $remote_branch_noprefix_arg brings back remote branch names prefixed with origin or their respective remote repository name.

Therefore, upgrading your shell or downgrading to a former version may be a good idea.

Some details yet:

  • I saw you've edited your original post and git push have good reasons to work slightly differently than git checkout ;
  • The homolog local branch of a remote one may not forcibly exists: feature is different from origin/feature, even when the former one, when it exists, is generally configured to track the latter ;
  • By default, if the local branch doesn't exist yet and when no explicit options are passed aside, checking out feature will create an eponym local branch configured to track the remote one, then switch to it, while checking out origin/feature will put you in detached mode, allowing to browse this remote branch but directly commit on top of it.
JJD
  • 44,755
  • 49
  • 183
  • 309
Obsidian
  • 2,760
  • 6
  • 14
  • 24
  • 1
    Thanks for the research effort! I checked the file on another machine where I run Ubuntu 18.04.2 with zsh 5.4.2. The order of arrays passed to `_alternatives` differs but I could worsen the completion behavior by removing `$remote_branch_noprefix_arg` temporarily. Now, I need to check the setup on the actual computer where I face the issue. I will let you know. – JJD Jul 02 '19 at 22:47
  • Thanks to you for your feedback. I've also noticed that this array order doesn't matter on my machine (probably parsed according to the patterns of their contents). Also, for information only, my Git version is the same (2.20.1). – Obsidian Jul 02 '19 at 22:58
  • On another machine I use zsh 5.1.1, Git 2.22.0 and Ubuntu 16.04. The order of arrays passted to `_alternatives` is the same as in your post. - What I noticed is that the branch completion does behave as expected for some branches whereas it behaves unexpected for others (as outlined in my question). I could not yet find a pattern, though. It might have something to do with whether I ever checked out a branch locally before or not. – JJD Jul 04 '19 at 09:38
  • Indeed, that's why somebody above asked for a `branch -a` to clarify which ones are already locally created or not. But even in this situation, my local's implementation still suggests me the "local" version of the branch, whether it already exists or not. – Obsidian Jul 04 '19 at 12:53
  • Maybe something is left behind when one had a local version of the branch and removed it. – JJD Jul 04 '19 at 14:32
  • Well I tested that too (with the rest above) and it didn't seem neither to alter the behavour observed so far… – Obsidian Jul 04 '19 at 14:48
  • Thank you for digging into the issue. I have still problems with reproducing the issue. I believe it does not make sense to discuss it as long as I cannot see the pattern. I will "pause" my question meanwhile. Thank you for your effort! – JJD Jul 04 '19 at 17:51
  • A BIG thank to you for validating the answer anyway and taking the time to feed back. Indeed it wasn't easy, and a real solution to this problem requires something much cleaner, I think, than tampering directly with _git. I'll try to find something on my side too and if I find, I'll raise up your entry with something valuable. Cheers ! – Obsidian Jul 04 '19 at 21:48
2

Note that since Git 2.23, you would use git switch instead of the confusing git checkout

And... before Git 2.27 (Q2 2020), the zsh command line completion would not work for git switch!

See commit 051cc54 (17 Apr 2020) by Terry Moschou (tmoschou).
(Merged by Junio C Hamano -- gitster -- in commit 7d96ac1, 28 Apr 2020)

complete: zsh: add missing sub cmd completion candidates

Signed-off-by: Terry Moschou

Add missing 'restore' and 'switch' sub commands to zsh completion candidate output. E.g.

$ git re<tab>
rebase    -- forward-port local commits to the updated upstream head
reset     -- reset current HEAD to the specified state
restore   -- restore working tree files

$ git s<tab>
show      -- show various types of objects
status    -- show the working tree status
switch    -- switch branches

And, with Git 2.28 (Q3 2020), the command line completion (in contrib/) learned to complete options that the "git switch" command takes.

See commit 9143992, commit acb658f, commit 00e7bd2, commit 6d76a5c, commit 68d97c7, commit 4e79adf, commit 6880779, commit 58a2ca3, commit 0408c6b, commit c81ca56, commit 7f59d60, commit b07d77a, commit c55b99c, commit e69fb0a, commit ab58e90, commit fab466f (28 May 2020) by Jacob Keller (jacob-keller).
(Merged by Junio C Hamano -- gitster -- in commit 3204218, 25 Jun 2020)

Example:

completion: improve handling of --detach in checkout

Signed-off-by: Jacob Keller

Just like git switch, we should not complete DWIM remote branch names if --detach has been specified. To avoid this, refactor _git_checkout in a similar way to _git_switch.

Note that we don't simply clear dwim_opt when we find -d or --detach, as we will be adding other modes and checks, making this flow easier to follow.

Update the previously failing tests to show that the breakage has been resolved.

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283