Uwe Geuder
Uwe Geuder

Reputation: 2315

How to list the change history of the directory tree in git

Git does not track directories as such. It only tracks files that live in some directory. (See How can I add an empty directory to a Git repository?)

However, if I have certain history of commits I implicitly also have history of changes to the directory tree.

So how do I answer questions like:

  1. when was directory foo/bar created (in git terminology: when was the first file created in that directory). There could be more than one qualifying commit if foo/bar has been deleted some time in history and recreated later.
  2. when was directory foo/bar removed (in git terminology: when was the last file removed from that directory). As above there could be more than one qualifying commit.
  3. what are the subdirectories of foo/bar that existed in any point of time in history

The closest I could come up with is in pseudo code:

loop over all commits (git rev-list --all)
  start from repo root directory
  do recursively on the directory tree rebuilt so far
    call git ls-tree and grep the tree lines
    rebuild next level of directory tree
  end
end

Obviously this could be written in your favorite scripting language.

Then I have all directory trees and I still need to search them in a smart way in order to be to answer questions of type 1 - 3. Again, doable but probably not in a couple of minutes.

The questions are:

  1. Is there an easier way?
  2. If not: are suitable the scripts already on the net? (my googling didn't reveal any, but I did not come up the perfect search words either)

Upvotes: 15

Views: 14359

Answers (2)

wadim
wadim

Reputation: 197

gitk foo/bar gives you a user interface for browsing the git history limited to commits that touched foo/bar.

Upvotes: 5

eckes
eckes

Reputation: 67177

For questions 1 and 2, it's quite easy:

  • when was directory foo/bar created?
    git log --oneline -- foo/bar | tail -n 1

  • when was directory foo/bar deleted?
    git log --oneline -- foo/bar | head -n 1

However, the third part is a bit tricky and I cannot answer it completely.

The two commands above give you $FIRST_REV (created) and $LAST_REV (deleted).

The following snippet gives you all commits where the tree was modified:

for rev in $(git rev-list FIRST_REV..LAST_REV)
do
  git ls-tree -r -t $rev | grep tree | cut -f 2
done

Then, you have a list of directories that were present. But there are still duplicates. Pass that list to a sort -u and you're done:

#!/bin/sh
for r in $(git rev-list FIRST_REV..LAST_REV) 
do 
    git ls-tree -r -t $r | grep tree | cut -f 2
done | sort -u

However, you lose the information of the commits where these directories were affected. That's the drawback.

And, this assumes that foo/bar was created only once and is no longer present.

Upvotes: 11

Related Questions