I'm very new to Git, and I'm trying to step through the commits from a repository. Rather than copy and pasting the SHA's for each commit, I'm using this method to get the next commit after the HEAD:

git checkout $(git rev-list HEAD..master | tail -n 1)

This works perfectly, but I'm using it a lot so I'd like to clean up the syntax a little with an alias.

First Attempt

In an ideal world, a function called something like "child-sha" would return the contents of the entire lookup so it could be called like this in powershell:

git checkout child-sha

If open up the /.config file, I can add the command by adding the following section:

[alias]
    child-sha = $(git rev-list HEAD..master | tail -n 1)

But when I execute it, I get the following error

Expansion of alias 'child-sha' failed; '$(git' is not a git command

Second Attempt

Okay, so no using $(). If I edit the config file as follows:

[alias]
    child-sha = rev-list HEAD..master | tail -n 1

Then call like this:

git checkout $(git child-sha)

Then I get the following Error

fatal: ambiguous argument '|': unknown revision or path not in the working tree

Third Attempt - Working, but sloppy

Okay, so no using the Pipe (|). If I update my config file like this:

git config --local alias.child-shas "rev-list HEAD..master"

Then I call like this:

get checkout $(git child-shas | tail -n 1)

Then it works, but I haven't saved that much space.

I'm not really sure what each of the functions in the script are doing as I'm really new to Git and Powershell commands in general. Google searches for the docs for using $, or | or tail don't reveal anything helpful as special characters are often stripped out of searches.

Is there any way to abbreviate this function?


In a separate inquiry, what I'm really looking to do is just step through every checkout so I can view the entire code base at that point in time so I can setup a small demo for a presentation. I doesn't seem as if any GUI editor (GitHub Windows, gitk, or Visual Studio Tools for Git) easily gives you the ability to checkout a particular commit; say, for example, by right clicking through the list of commits.

You're missing the basic trick that (see "unless" in a moment) git aliases are just direct git-only commands, with no shell involved and no ability to run non-git commands:

[alias]
    foo = checkout

unless preceded by a shell escape ! character:

[alias]
    bar = !git checkout

(at this point both aliases mean the same thing). Since you want the shell to get involved, so as to run sub-commands $(...) and pipes ... | ...—these are all "shell" things, not "git" things—you need the ! prefix syntax. All the rest of your experimentation will then go much better.


That said, addressing your base problem: I know little about most GUI editors, but in gitk you can select any revision you like in the topmost pane, click the "tree" selector in the lower right pane, and then select any file in the tree (going through directories as needed) to view the file in the lower left pane. It's true that this will not get you the whole tree, of course, just one file at a time. (Click back on the "patch" selector to go back to viewing patches.)

The other thing I would do here is to avoid these HEAD-relative operations when possible: instead of "step forward one" (which is tricky), you can start from a known fixed point—or at least, fixed for the duration of the demo—such as a branch name, and use git's revision syntax (see gitrevisions) to select commits however far back you mean:

git checkout master~5
... demonstrate something ...
git checkout master~4
... demonstrate next thing ...

The <code>~<i>n</i></code> syntax tells git to count backwards for n parents, following only first-parent links in case of merge commits. Since 4 is one less than 5, master~4 is necessarily one hop closer to master than master~5. (If there are merges, the two items being merged are the same distance, hop-wise, from whatever starting point you choose, so this particular method is too simple to capture the truth. You can start doing master~3^2~2 for instance, but it gets quite messy.)