15

I am using zsh shell and prezto with cygwin. When I type this git command:

git reset HEAD5

zsh returns:

zsh: no matches found: HEAD^

But when I switch to use bash shell, it works.

Why does zsh throw an error when I try to use HEAD^?

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
michael
  • 106,540
  • 116
  • 246
  • 346

4 Answers4

32

The ^ character is treated as special in filename expansions in zsh, but only if the EXTENDED_GLOB option is set:

zsh% setopt noEXTENDED_GLOB
zsh% echo HEAD^
HEAD^
zsh% setopt EXTENDED_GLOB
zsh% echo HEAD^
zsh: no matches found: HEAD^
zsh% 

Bash doesn't have this feature. (To be precise, bash does have an extended glob feature, enabled by shopt -s extglob, but bash's extended glob syntax doesn't treat the ^ character as special.)

With this feature enabled, ^ is a special character similar to * but with a different meaning. Like *, you can inhibit its special meaning by escaping it, either by enclosing it in single or double quotes or by preceding it with a backslash. Quoting is the simplest solution.

Rather than

git reset HEAD^

try this:

git reset 'HEAD^'

The meaning of the ^ wildcard is not relevant, since all you need to do is avoid using it, but I'll mention it anyway. According to the zsh manual, ^X matches anything except the pattern X. For the case of HEAD^, nothing follows the ^ -- which means that HEAD^ matches HEAD followed by anything other than nothing. That's a roundabout way of saying that HEAD^ matches file names starting with HEAD and followed by some non-empty string. Given files HEAD, HEAD1, and HEAD2, the pattern HEAD^ matches HEAD1 and HEAD2.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
6

A quick workaround to avoid the ^ character is to use git reset head~1 instead of git reset head^.

See this post for the difference between the two.

Community
  • 1
  • 1
Andrew
  • 7,848
  • 1
  • 26
  • 24
4

issue 449 of oh-my-zsh describes this exact behaviour and provides the solution.

The culprit is the option extended_glob on zsh. Presto must be setting it. So when you type HEAD^ zsh tries to create a glob negation expression and fails with an error.

In other words, setopt extended_glob allows us to use ^ to negate globs.

To fix it, you can write this line on your .zshrc:

unsetopt nomatch 

With the above line, we are saying to zsh we want that when pattern matching fails, simply use the command "as is".

ninrod
  • 523
  • 6
  • 25
  • Not recommended to unset `nomatch` just to avoid this error. This will have knock-on behaviour for all other shell code that the user might not want or expect. It's probably better to quote the string `git reset "HEAD^"`, escape the character `git reset HEAD\^` or use a tilde if it's appropriate `git reset HEAD~1` – Zorawar Mar 22 '17 at 16:49
  • I don't see a problem with that since scripts can use `#!/usr/bin/env zsh -f` and I'm not sure that using `#!/usr/bin/env zsh` makes the script pick up configuration from `~/.zshrc`. If it does that could be a problem. And even then the script should set it's own options just to be sure. It should not be dependent on users specific configurations. – ninrod Mar 22 '17 at 22:20
  • That's true, but I would still hesitate doing it on my system at least because it changes the expected behaviour of globbing patterns that could catch you out if you're not mindful. For example, `var=(*.fooext)` with `nomatch` unset will not produce an error if the glob match fails, it will instead create a string called "*.fooext" in the `var` array. And that might not be what you expect. Then again, these might just be edge cases, and I guess it's up to the user to decide for themselves the system they want... – Zorawar Mar 22 '17 at 23:53
  • 1
    `sh` and `ksh` don't default to abort on glob mismatch from the zsh docs, so I think most script tend to target `sh` compatibility maybe? – Didier A. Aug 14 '21 at 07:33
0

On Mac escape the ^ in your command:

git reset --soft HEAD\^
Hamada
  • 1,836
  • 3
  • 13
  • 27