How to list the change history of the directory tr

2020-08-09 11:09发布

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)

标签: git
2条回答
smile是对你的礼貌
2楼-- · 2020-08-09 11:44

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.

查看更多
Lonely孤独者°
3楼-- · 2020-08-09 11:45

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

查看更多
登录 后发表回答