Two or three weeks ago I noticed a problem with Magit. When I executed magit-status
, I no longer got a list of the untracked files. That meant that I couldn’t add new files to a repository with Magit. The thing was if I switched to Eshell
and called git
directly, everything worked correctly. “Well, no problem,” I thought, “the latest commit must have broken something. They’ll get it fixed soon.” In the mean time, I just added the new files by calling git
directly. But despite almost daily updates to Magit, the problem didn’t go away, so I asked DuckDuckGo what it knew about the problem. Answer: nothing. Nobody else was having the problem so it must be something local. I hadn’t changed anything in my init.el
or messed with the Emacs or git
configurations in any way so I decided to jump into the code to figure out where I was failing.
Initially I thought I would run the debugger but it was pretty clear from the code that the problem had to be in magit-insert-untracked-files
, which in turn meant that magit-git-lines
was failing. The magit-git-lines
function just calls git
with the specified parameters (via process-file
) so it looked like git
was failing but it worked fine when I called it with the same parameters that magit-insert-untracked-files
was using.
There are two points to this post. Here’s the first: Because Emacs is a Lisp machine-like environment, I could make the same call to process-file
that magit-git-lines
was making by typing 【Meta+:】 and entering the call in the minibuffer. That call failed as expected but I was able to play with the parameters to git
to see where the problem lay. The actual call that was failing was
git --no-pager status --porcelain -u
and by eliminating the parameters one by one I discovered that it was the --porcelain
parameter that was causing the problem. That parameter asks git
to output the results in a machine-parsable format that is guaranteed to be backward compatible. Just what you need for an application like Magit.
It became pretty clear what the problem was. There must be an old version of git
that didn’t implement the --porcelain
option on my machine. I checked that by changing the parameter to the git
call to --version
and discovered it was calling version 1.6.5.7. When I called
git --version
from Eshell, I got 1.8.3.4.
So here’s what happened. These days git
is either included in the OS or gets loaded with Xcode but that didn’t use to happen so I built my own version and installed it in ~/bin
, a directory where I keep my executables. Because I add ~/bin
to (the head of) exec-path
, Emacs was finding the old version. Eshell doesn’t use exec-path
so it was finding the newer version. That brings me to the second point: I’m telling you all this in case you experience the same problem. Just get rid of the old git
executables and you’ll be fine.
It’s worth reiterating the first point. The wonderful Emacs Lisp environment makes it easy to debug problems like this. You can just try executing code until you find where it’s failing. No recompiling, no reloading, just try it and see what happens. Think what it would be like solving this problem if it were a C program.