A Problem with Magit

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.

This entry was posted in General and tagged . Bookmark the permalink.