有没有办法知道或获取原始创建/修改时间戳?
有没有办法知道或获取原始创建/修改时间戳?
是的,元数据存储库或 git-cache-meta 可以存储这样的(元)信息! Git 本身无法存储它。 Metastore 或 git-cache-meta 可以为文件存储任何文件元数据。
这是元数据存储库或 git-cache-meta 的设计初衷,旨在支持备份工具和同步工具,同时也支持此目的。
find
的 -printf
扩展,而我几乎可以确定 metastore(作为一个 C 项目)更难以移植。非常不幸。如果我发现情况有所改变,我会在这里回复的。 - Steven Lugit-cache-meta
的更新版本并已转化为一个仓库;现在可以将其安装为 git 钩子,这样每次提交时都会自动存储元数据! - dani 'SO learn value newbies'# No arguments? Recursively list all git-controlled files in $PWD and start over
if [ $# = 0 ]; then
git ls-files -z |xargs -0 sh "$0"
exit $?
fi
for file in "$@"; do
time="$(git log --pretty=format:%cd -n 1 \
--date=format:%Y%m%d%H%M.%S --date-order -- "$file")"
if [ -z "$time" ]; then
echo "ERROR: skipping '$file' -- no git log found" >&2
continue
fi
touch -m -t "$time" "$file"
done
这个命令接受特定的文件作为参数,否则会更新当前目录或其子目录中的每个git控制的文件。这样做可以允许文件名中包含空格甚至换行符,因为git ls-files -z
输出以null结尾的文件列表,而xargs -0
将null结尾的列表解析为参数。
如果你有很多文件,这可能需要一些时间。
不,Git 根本不会存储这种(元)信息,除非您使用第三方工具,如metastore或git-cache-meta。唯一存储的时间戳是创建补丁/更改的时间(作者时间)和创建提交的时间(提交者时间)。
这是出于设计考虑,因为Git是版本控制系统,而不是备份实用程序或同步工具。
git-restore-mtime
。
Ubuntu和Debian: sudo apt install git-restore-mtime
Fedora、Red Hat Enterprise Linux(RHEL)和CentOS: sudo yum install git-tools
更多详情请参见我的另一个回答。
免责声明:我是git-tools
的作者
这个Python脚本可能有所帮助:对于每个文件,它应用了文件被修改的最近提交的时间戳:
下面是一个非常简单版本的脚本。对于实际使用,我强烈建议使用上述更健壮的版本之一:
#!/usr/bin/env python
# Bare-bones version. The current directory must be top-level of work tree.
# Usage: git-restore-mtime-bare [pathspecs...]
# By default update all files
# Example: to only update only the README and files in ./doc:
# git-restore-mtime-bare README doc
import subprocess, shlex
import sys, os.path
filelist = set()
for path in (sys.argv[1:] or [os.path.curdir]):
if os.path.isfile(path) or os.path.islink(path):
filelist.add(os.path.relpath(path))
elif os.path.isdir(path):
for root, subdirs, files in os.walk(path):
if '.git' in subdirs:
subdirs.remove('.git')
for file in files:
filelist.add(os.path.relpath(os.path.join(root, file)))
mtime = 0
gitobj = subprocess.Popen(shlex.split('git whatchanged --pretty=%at'),
stdout=subprocess.PIPE)
for line in gitobj.stdout:
line = line.strip()
if not line: continue
if line.startswith(':'):
file = line.split('\t')[-1]
if file in filelist:
filelist.remove(file)
#print mtime, file
os.utime(file, (mtime, mtime))
else:
mtime = long(line)
# All files done?
if not filelist:
break
所有版本都解析单个git whatchanged
命令生成的完整日志,这比每个文件循环快数百倍。对于Git(24,000个提交,2,500个文件),时间不到4秒,对于Linux内核(40,000个文件和300,000个提交)则不到一分钟。
$ python ./git-restore-mtime
如果出现以下错误:Traceback (most recent call last):
File "./git-restore-mtime", line 122, in
'git rev-parse --show-toplevel --git-dir')).split('\n')[:2]
TypeError: Type str doesn't support the buffer API
请问需要使用哪个版本的Python?我正在使用3.3.3。 - Rolf这对我在Ubuntu上起了作用(因为Ubuntu缺少date(1)中的OS X“-j”标志):
for FILE in $(git ls-files)
do
TIME=$(git log --pretty=format:%cd -n 1 --date=iso $FILE)
TIME2=`echo $TIME | sed 's/-//g;s/ //;s/://;s/:/\./;s/ .*//'`
touch -m -t $TIME2 $FILE
done
-d
标志,而不是-t
。所以:for FILE in $(git ls-files) ; do TIME=$(git log --pretty=format:%cd -n 1 --date=iso $FILE) ; touch -m -d "$TIME" $FILE ; done
- Richard Walker本地的Git没有这个功能,但可以通过钩子脚本或第三方工具实现。
我尝试过metastore
。它非常快,但我不喜欢需要安装和元数据不以纯文本格式存储的需求。git-cache-meta
是一个简单的工具,但对于大型存储库(对于拥有数万个文件的存储库,更新元数据文件需要几分钟)来说速度极慢,并且可能存在跨平台兼容性问题。 setgitperms
和其他方法也有其缺点,我不喜欢。
sort
和Git所需的perl
,以及可选的chown
,chgrp
和touch
),因此对于可以运行Git的平台不需要安装任何其他内容,具有理想的性能(对于包含成千上万个文件的存储库,更新元数据文件只需< 10秒;虽然创建需要更长时间),以纯文本格式保存数据,并且要“保存”或“加载”的元数据是可定制的。
它对我很好用。如果您对metastore、git-cache-meta和其他方法不满意,请尝试使用此方法。
--install
钩子似乎直到我手动运行git-store-meta.pl --store
第一次才开始工作。 - Milind R--init
标志如何?这样钩子就可以正常工作了。只是一个建议... - Milind R我已经在与git和文件时间戳搏斗了一段时间。
测试了一些你的想法,并制作了自己庞大且占用内存较多的脚本,直到我在某个git wiki上找到了一个perl脚本,它几乎做到了我想要的。
https://git.wiki.kernel.org/index.php/ExampleScripts我想要的是能够基于提交日期保留文件的最后修改时间。
所以经过一些调整,该脚本能够在约2-3分钟内更改200k个文件的创建和修改日期。
#!/usr/bin/perl
my %attributions;
my $remaining = 0;
open IN, "git ls-tree -r --full-name HEAD |" or die;
while (<IN>) {
if (/^\S+\s+blob \S+\s+(\S+)$/) {
$attributions{$1} = -1;
}
}
close IN;
$remaining = (keys %attributions) + 1;
print "Number of files: $remaining\n";
open IN, "git log -r --root --raw --no-abbrev --date=raw --pretty=format:%h~%cd~ |" or die;
while (<IN>) {
if (/^([^:~]+)~([^~]+)~$/) {
($commit, $date) = ($1, $2);
} elsif (/^:\S+\s+1\S+\s+\S+\s+\S+\s+\S\s+(.*)$/) {
if ($attributions{$1} == -1) {
$attributions{$1} = "$date";
$remaining--;
utime $date, $date, $1;
if ($remaining % 1000 == 0) {
print "$remaining\n";
}
if ($remaining <= 0) {
break;
}
}
}
}
close IN;
针对Windows环境,我使用Delphi 10.1 Berlin编写了一个小型(快速且简单)的EXE文件,将源代码树中的所有文件日期收集到.gitfilattr文件中,并可以再次应用于已检出的源代码树。
代码在GitHub上:
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
我在基于GitLab runners的构建系统中使用它。
我希望你能欣赏这种简洁:
# getcheckin - Retrieve the last committed checkin date and time for
# each of the files in the git project. After a "pull"
# of the project, you can update the timestamp on the
# pulled files to match that date/time. There are many
# that believe that this is not a good idea, but
# I found it useful to get the right source file dates
#
# NOTE: This script produces commands suitable for
# piping into BASH or other shell
# License: Creative Commons Attribution 3.0 United States
# (CC by 3.0 US)
##########
# walk back to the project parent or the relative pathnames don't make
# sense
##########
while [ ! -d ./.git ]
do
cd ..
done
echo "cd $(pwd)"
##########
# Note that the date format is ISO so that touch will work
##########
git ls-tree -r --full-tree HEAD |\
sed -e "s/.*\t//" | while read filename; do
echo "touch --date=\"$(git log -1 --date=iso --format="%ad" -- "$filename")\" -m $filename"
done