Opening All Files in a Git Commit

Sometimes even Linux crashes, or a machine loses power, in which case applications lose their history.

This has been an annoyance for me with Emacs and a project that I’m working on that is version controlled with Git, or perhaps I just want to open all of the files in a commit so that they are the most recent in my list of open files in Emacs.

Finally I’ve devised a one line solution, as is noted below.

The first step is to get a list of files from the most recent Git commit, with the output being only the file names — no commit message, author, committer, etc.. Easy enough, where --pretty=format: means “write no commit summary output”:

% git log --git log --name-only --pretty=format: -1

This will be fed into the command to open a file in Emacs, which in my case is function named ec. This is Z shell, but should work for Bash.

ec () {
    for i in $*
        emacsclient --no-wait $i

Why a function and not an alias? Because evidently emacsclient only takes one file name as an argument, so it needs to be called once for each file.

Since ec is a function (and the same restriction applies to aliases as well), it cannot be a command executed by xargs, which would have been:

% git log --name-only --pretty=format: -1 | xargs ec

which produces the message “xargs: ec: No such file or directory”.

The fix is to read each line into a variable, then run the function against it. Voila:

% git log --name-only --pretty=format: -1 | while read -r i; do ec $i; done

More of my Z shell blatherings are over here.

New Z shell blog

I’ve started a blog exclusively about the astonishingly powerful Z shell.

Check it out here: Focus on Zsh.

The goal is to find some of the more interesting and complex examples of Zsh code, and to break them down, explaining them line by line. Despite having worked with Zsh for many years (over a decade), I consider that I’ve barely scratched the surface of what it can do, and, not finding many instructive Zsh resources, have decide to create one.

Please take a look, and I look forward to your feedback.

A for Alias

In Zsh (and other shells), aliases may be the most important feature for increased productivity.

A simple rule is this: the more often you run a command, the shorter it should be. I’ve written about this before, in Efficient Way to Improve Console Productivity.

I have a number of one-character aliases:

G='| glark'
H='| head'
L='| less'
M='| more'
S='| sort'
T='| tail'
h='history -5000'
l='ls -CF'

I’ll write later about those nifty uppercase ones (and yes, there is the alias “a” for “alias”, but for now, I’ll just show them with examples:

alias G -g '^.='

That was the command that I ran to generate the list above. It expands to “alias | glark -g ‘^.='”.

find src -type d S

That finds all directories and pipes them to sort.

There are three “families” of commands that I run the most often:

  • diff – diff files
  • eye – look at/in files on the command line
  • find – list all files/directories matching a pattern
  • open – open files in editor, browser
  • search – look in files

So I have been writing one-character scripts/functions (in Bash) for each of the above, where the script understands context as well as the targets.

For example, “s pluralize” run from a directory that contains a “Rakefile” will expand to search (using glark) only for Ruby files.

e program.tar.gz” is the equivalent of “tar ztvf program.tar.gz“, and “e” lists the zip file, with entries sorted by name.

d dir1 dir2” runs a recursive diff on the directories, and “d path/to/file ../dir2” will diff “path/to/file” against “../dir2/path/to/file”, if the latter file exists. I do this to avoid the tedious repetition of comparing one code base to another (such as two branches, when merging them): “diff path/to/file1 ../dir2/path/to/file1“, “diff path/to/file2 ../dir2/path/to/file2“, etc.

Although this project is in its early stage, and the output is still rough (i.e., containing debugging output), it already has been quite useful, so I thought I would share.

The project is at Github here.