Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use zsh tab completion on Git without origin?

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

like image 547
JJD Avatar asked Apr 16 '19 22:04

JJD


2 Answers

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.

like image 177
VonC Avatar answered Sep 28 '22 15:09

VonC


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.
like image 38
Obsidian Avatar answered Sep 28 '22 16:09

Obsidian