Search code examples
gitgit-bare

Get a tree of files in a bare git repo on at a specific commit


You can use git ls-tree --full-tree -r HEAD on a bare repo to get all the files in that repo, but I want that list for specific commits.

I.e. I want to walk though a repo commit by commit from the first commit until I'm at HEAD and see how the file tree has evolved. I only care about the files and paths, I don't actually care about the contents.

Is there a way to do this on a bare repo? I want this on a bare repo because we have some very large repos and doing a checkout for each commit would be far too costly in CPU time.


Solution

  • Sure, just replace HEAD with any commit-or-tree identifier, such as an SHA-1 or any of the specifiers allowed by gitrevisions.

    To get SHA-1 IDs, use git rev-list. For instance, to work from the current commit (HEAD) back to the root following only first parents at each merge:

    git rev-list --first-parent --topo-order HEAD | while read rev; do
        git ls-tree --full-tree -r $rev
    done
    

    To run through the same set of revisions in the other order, add --reverse to the arguments to git rev-list.

    If you want to follow all parents at merges, you can simply omit --first-parent. The --topo-order restriction will ensure that parent commit IDs come before (or with --reverse, after) all their children. Without a specific sort, you get the commits in reverse (or with --reverse, forward) order by commit-date.

    (If you're going to track the tree as it evolves but also want to handle merges nicely, you may need a more complex operation here, where you have git rev-list produce the parent and child commit IDs together, since even with --topo-order or some other sorting criterion keeping parent/child relationships together, it's not going to be obvious, from a flattened graph, exactly where the merge happened. Read the git rev-list documentation thoroughly for this. Using --first-parent simplifies the job enormously since it gives you a simplified, strict parent/child ordering.)