ChatGPT解决这个技术问题 Extra ChatGPT

Complex Git branch name broke all Git commands

I was trying to create a branch from master with the following command,

git branch SSLOC-201_Implement___str__()_of_ProductSearchQuery

when Git suddenly stopped responding. I suspect the unescaped () are to blame, somehow. Now, whenever I try to run any Git command, I get the same error:

git:176: command not found: _of_ProductSearchQuery

with the number after git increasing every time I type a command.

Can anyone explain what happened? And how do I get back to normal? I'd like to delete that branch, but how can I do that?

I would guess this is related to your zsh environment as I was able to run create the branch in my bash shell with no ill side-effects (lubuntu 13.10), but I'm seeing the error when I switch to my totally vanilla zsh
In the future, quote stuff that looks suspect. git branch "SSLOC-201_Implement___str__()_of_ProductSearchQuery" works just fine.
@Qix Better to avoid problematic characters altogether.
@Jubobs Definitely, though I've seen certain companies enforce weird branch names like this.
@DwightSpencer Your link is specific to Bash, but this question is zsh-specific. The problem doesn't actually occur in Bash.

C
Community

Problem

Can anyone explain what happened? [...] I'd love to be able to delete that branch, but Git won't work for me.

By running

git branch SSLOC-201_Implement___str__()_of_ProductSearchQuery

in zsh, you did not create any branch. Instead, you accidentally defined three shell functions, called git, branch, and SSLOC-201_Implement___str__, which ignore their parameters (if any) and whose body is _of_ProductSearchQuery. You can check for yourself that this is indeed what happened, by invoking the builtin zsh command called functions, which lists all existing shell functions:

$ functions                                                     
SSLOC-201_Implement___str__ () {
    _of_ProductSearchQuery
}
branch () {
    _of_ProductSearchQuery
}
git () {
    _of_ProductSearchQuery
}

Unfortunately, although the other two shell functions are not problematic, the shell function called "git" now shadows the bona fide git command!

$ which git
git () {
    _of_ProductSearchQuery
}
# but the real "git" is a binary file that lives in /usr/local/bin/git (or some similar path)

Therefore, you will subsequently get the error

command not found: _of_ProductSearchQuery

whenever you attempt to run a Git command, e.g. git log, git status, etc. (assuming, of course, that no command called _of_ProductSearchQuery exists).

Side note

[...] I get the same error: git:176: command not found: _of_ProductSearchQuery (with the number after git increasing every time I type a command)

That number simply corresponds to the value of HISTCMD, an environment variable that holds

[t]he current history event number in an interactive shell, in other words the event number for the command that caused $HISTCMD to be read.

See the zsh manual for more details.

Solution

And how do I get back to normal?

Simply delete the problematic shell function (and the other two you created by accident, while you're at it):

unset -f git
unset -f branch SSLOC-201_Implement___str__

Then everything should be fine.

What if unset is shadowed also?!

Good question! I refer you to Wumpus W. Wumbley's excellent comment below.

Branch-naming tips

Avoid any special shell characters

Yes, as pointed out in the comments, parentheses are valid characters in Git branch names; you just need to quote the name appropriately, e.g.

$ git branch 'foo()bar'
$ git branch
  foo()bar
* master
$ git checkout 'foo()bar'
Switched to branch 'foo()bar'

However, the need for quoting such names every single time when used as command-line arguments should convince you to eschew parentheses in reference names. More generally, you should (as much as possible) avoid characters that have a special meaning in shells, to prevent surprises like this one.

Use simple branch names

You should keep your branch names short and sweet anyway. Long descriptions like

SSLOC-201_Implement___str__()_of_ProductSearchQuery

belong in commit messages, not in branch names.


Nothing in that thread states parens are illegal. Git seemed to like it just fine. Switched to a new branch 'abcd-()-foo'
Looks good; definitely not a great idea to use them, but they're not technically invalid.
What happens if someone also shadows unset by creating shell function so called? (is this possible?)
@codroipo Ha! That's a good point. Yes, it is possible, and, in that case, you're probably better off restarting zsh.
You could use builtin unset. If builtin and unset have both been shadowed by functions, then unfunction. If that's gone too, unhash -f. If all four of those are gone, then restart the shell.