19

The following commands

$ git co -b newbranch
$ git co oldbranch

result in "fatal: cannot exec 'git-co': Permission denied" error.

In the same time,

$ git checkout -b newbranch
$ git checkout oldbranch

and

$ sudo git co -b newbranch
$ sudo git co oldbranch

work as expected. Ownership rights for the .git folder are set for the user owning the home folder and 0755/0644 are the mode for .git folder/subfolder/files. There are no git-co script anywhere in the system (that is an expandable alias to git-checkout, which resides in /usr/libexec/git-core` dir).

Aliases are defined in .gitconfig of the home folder:

[alias]
co = checkout

There is no difference in git config -l output for root or unprivileged user. Still sudo git co oldbranch works and git co oldbranch does not.

What am I missing?

Gentoo / kernel 3.0.6 / git 1.7.3.4

8
  • where are the aliases? are they invoking scripts?
    – sehe
    Commented Nov 3, 2011 at 15:43
  • Attach the output of git config --get-regexp '^alias\.'
    – manojlds
    Commented Nov 3, 2011 at 15:57
  • @AlexeiDanchenkov: erm... not to state the obvious but "where are the aliases" (we can't see them)
    – sehe
    Commented Nov 3, 2011 at 16:05
  • 1
    Look in your git install directory; I don't know gentoo but it's probably /usr/libexec/git-core, /usr/lib/git-core or one of those with /usr changed to /usr/local. You should see a bunch of executable files for all the git commands. See if there's also a git-co in there, which is executable by root but not by you. Possibly this could also happen if this git-co file is somewhere in your PATH. It might also be locatable with sudo which git-co, if it's not in the git install directory.
    – Cascabel
    Commented Nov 3, 2011 at 17:00
  • @mahojlds alias.co checkout Commented Nov 3, 2011 at 17:01

3 Answers 3

25

The correct answer to this was actually different. Before git runs the aliases it checks the $PATH. In case the directory does not exist, or lacks permissions, git produces the "fatal: cannot exec 'git-co': Permission denied". It does not ever comes to check the aliases so git foobar will produce the same error.

Good people from the git mailing list also reminded me of an strace tool, that can help finding the entry that is returning EACCES, as in: strace -f -e execve git foobar

The credit goes to Jeff King from the git mailing list. :)

6
  • 7
    I'm on Gentoo w/ git 1.7.3.4 and no public execute permissions on /usr/games/bin was causing this for me. It was in my path and Git failed to find proper permissions on a dir in my PATH so it produced this error for an alias. chmod +x /usr/games/bin was all it took to fix it right up for me. Grabbed this one-liner to quickly view PATH permissions echo $PATH |tr ':' '\n' |xargs ls -ld
    – SleighBoy
    Commented Dec 20, 2011 at 20:07
  • Good catch! Glad you found the right answer. Sure enough, adding a directory to PATH that does not have execute permissions set will cause running git with a non-builtin command to give a fatal: cannot exec 'git-hist': Permission denied error. I'm using Git version 1.7.8; hopefully a fix will be available soon.
    – Go Dan
    Commented Dec 21, 2011 at 18:46
  • 2
    or better yet: strace -f -e execve git foobar 2>&1|grep -i denied
    – sivann
    Commented May 21, 2012 at 19:45
  • Exactly my issue, too. My PATH is preset with dozens of dirs (only a few of which are bad) sourced from /etc scripts out of my control (e.g., remote storage not always available). To quickly reset the path to just valid dirs: PATH=$(for d in ${PATH//:/ } ; do [ -x $d ] && printf "$d\n"; done | uniq | tr '\12' ':') (and to trim the trailing :, follow with PATH=${PATH%?})
    – michael
    Commented Mar 13, 2013 at 4:06
  • What do you mean when you say an entry that is returning "EACCES"?
    – camdixon
    Commented Mar 28, 2014 at 18:16
8

Is it possible you have inadvertently created a non-executable git-co file somewhere? I can recreate your situation if I do just that, as demonstrated below.

$ git --version
git version 1.7.7.1.475.g997a1
$ git config --get-regexp '^alias\.co$'
alias.co checkout
$ git co b1
Switched to branch 'b1'
$ touch $HOME/bin/git-co
$ ls -al $HOME/bin/git-co
-rw-r--r-- 1 user user 0 2011-11-03 12:59 /home/user/bin/git-co
$ git co master
fatal: cannot exec 'git-co': Permission denied
$ for p in $(echo "$PATH" | sed -e 's/:/ /g'); do if [ -f "${p}/git-co" ]; then echo "Found git-co in ${p}"; fi; done
Found git-co in /home/user/bin
$ rm $HOME/bin/git-co
rm: remove regular empty file `/home/user/bin/git-co'? y
$ git co master
Switched to branch 'master'

Another thing you might want to try is enabling trace logging to get more information about what Git is doing. Following is an example:

GIT_TRACE=$HOME/trace.log git co master

You must use absolute paths if you want to send output to a file. Otherwise, use true or 1 to send output to standard error; e.g. GIT_TRACE=1. The trace.log file contains:

trace: exec: 'git-co' 'master'
trace: run_command: 'git-co' 'master'
trace: alias expansion: co => 'checkout'
trace: built-in: git 'checkout' 'master'

If you do not see the trace: alias expansion: co=> 'checkout' trace log output, Git is finding a git-co file in the PATH environment variable. Git uses a PATH as follows:

  1. Start with an empty PATH, saving any "old" PATH for reference.
  2. If the --exec-path=<my git commands path> Git option is found, append <my git commands path> to the PATH.
  3. If --exec-path=<my git commands path> was not found and the GIT_EXEC_PATH environment variable is set, append this to the PATH.
  4. If you called git using a relative or absolute path, append the absolute path of the git executable to the PATH.
  5. If PATH was previously defined, append it to the PATH.
  6. If PATH was not previously defined, append /usr/local/bin:/usr/bin:/bin to the PATH.

You can use another alias to get Git to tell you what it is setting the PATH environment variable to.

$ git config --global alias.whatpath '!echo $PATH'
$ git whatpath
/usr/local/libexec/git-core:/home/user/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Then check each directory listed for the existence of a git-co file. It's not sufficient to do which git-co and assume that if nothing is found that you do not have a git-co file located in one of the directories in Git's PATH; a file may exist that is not executable and which will not display it.

4
  • This is not the case. I checked this already, but nope... The for loop in your example returns nothing. Commented Nov 3, 2011 at 17:46
  • You could also check for a git-co file in the directory that git --exec-path displays. As well as using find / -name git-co to check your whole system (obviously, use with care).
    – Go Dan
    Commented Nov 3, 2011 at 17:54
  • Thanks, Dan. There is a /usr/libexec/git-core/git-checkout file with proper permissions, but there us no git-co anywhere. My assumption is that the alias is not working. But it works for root... Getting desperate. Commented Nov 3, 2011 at 18:01
  • Dan, that was closer, the trace.log stops at step 3 (alias expansion), i.e. the trace: alias expansion: co => 'checkout' never appears for an unprivileged user. It does for the root. The traceSetup.log never appears in neither case. Commented Nov 3, 2011 at 20:12
1

Check to see if you have execute permissions on the git aliases. Providing the execute permissions solved this issue for me.

I downloaded "git-credential-osxkeychain" and added it to /usr/local/bin and provided the exec rights and could run the command without any issue.

Not the answer you're looking for? Browse other questions tagged or ask your own question.