follow a directory which has been renamed?
The git command has a useful command to follow a file after a rename, as in git log --follow path/to/some/file
. Unfortunately, it works only for an individual file. I'd like to be able to do the equivalent of git log --follow some/directory
.
One way of doing this would probably be to massage the output of git ls-tree
and do that in a loop, but the problem then becomes that commits affecting multiple files won't be "coalesced" into one commit.
Is there a better way to do it? Note: using git 2.7.4
No.
Git does not store directories, only files. When you use any path name to commands like git log
or git diff
that look at entire commits, Git essentially says "start with the whole commit, then shrink it down to file(s) matching that path". Directories here simply wind up selecting every file in the directory.
The --follow
option can only follow one file. So if you could somehow manage to get it to apply to a directory, Git would first turn the directory into a set of files, then pick one of those files and follow just that one.
(The actual --follow
code is terribly hacky. It leverages off the rename detection code, but only works when commits are being compared in the newer-to-older order: if you add --reverse
, --follow
never works at all. Probably the whole thing needs to be thrown out and re-coded. Perhaps by re-coding it, you could make it handle multiple file names, and even directories full of files.)
There does not seem to be a builtin way to do this.
One can do this using a script and following a simple algorithm:
Here's a hacky way to do it using python 3 and the sh
module, won't work on Windows for various reasons.
#!/usr/bin/env python3
import os
import shlex
import sys
import tempfile
import sh
def _get_commits(fname):
# Ask for the commit and the timestamp
# .. the timestamp doesn't guarantee ordering, but good enough
for c in sh.git('log', '--follow', '--pretty=%ct %h', fname,
_tty_out=False, _iter=True):
c = c.strip().split()
yield int(c[0]), c[1]
def git_log_follow_multi(filenames):
if len(filenames) == 0:
print("Specify at least one file to log")
elif len(filenames) <= 1:
os.system('git log --follow -p %s' % filenames[0])
else:
# Use git log to generate lists of commits for each file, sort
commits = []
for fname in filenames:
commits += _get_commits(fname)
# Sort the lists (python's sort is stable)
commits.sort(reverse=True)
# Uniquify (http://www.peterbe.com/plog/uniqifiers-benchmark)
seen = set()
seen_add = seen.add
commits = [c for c in commits if not (c in seen or seen_add(c))]
# Finally, display them
tname = None
try:
file_list = ' '.join(shlex.quote(fname) for fname in filenames)
with tempfile.NamedTemporaryFile(mode='w', delete=False) as fp:
tname = fp.name
for _, commit in commits:
fp.write('git log -p -1 --color %s %sn' % (commit, file_list))
# Use os.system to make our lives easier
os.system('bash %s | less -FRX' % tname)
finally:
if tname:
os.unlink(tname)
if __name__ == '__main__':
git_log_follow_multi(sys.argv[1:])
Now, this script doesn't exactly meet your needs since it takes a list of files, but you can execute it using a glob and it'll do what you're looking for.
./script.py src/*
链接地址: http://www.djcxy.com/p/92786.html
上一篇: 由于CPU不足,Pod处于挂起状态
下一篇: 跟随一个已经重命名的目录?