有什么办法知道或获取原始的创建/修改的时间戳吗?谢谢。
有什么办法知道或获取原始的创建/修改的时间戳吗?谢谢。
Answers:
我相信,Git数据库中记录的唯一时间戳是作者和提交时间戳。我看不到Git修改文件时间戳以匹配最新提交的选项,并且这不是默认行为是有道理的(因为如果这样,Makefile将无法正常工作)。
您可以编写脚本来将文件的修改日期设置为最近一次提交的时间。它可能看起来像这样:
IFS="
"
for FILE in $(git ls-files)
do
TIME=$(git log --pretty=format:%cd -n 1 --date=iso -- "$FILE")
TIME=$(date -j -f '%Y-%m-%d %H:%M:%S %z' "$TIME" +%Y%m%d%H%M.%S)
touch -m -t "$TIME" "$FILE"
done
是的,metastore或git-cache-meta可以存储此类(元)信息!没有第三方工具,Git本身无法做到。Metastore或git-cache-meta可以存储文件的任何文件元数据。
这是设计使然,因为metastore或git-cache-meta正是用于该目的,并支持备份实用程序和同步工具。
(对不起,Jakub的回答有点有趣)
find的-printf扩展,而且我几乎可以肯定,使metastore(作为C项目)在使可移植性方面需要做更多的工作。相当不幸。如果发现这种情况发生了变化,我将在此发布。
否,除非您使用诸如metastore之类的第三方工具,否则Git根本不会存储此类(元)信息或git-cache-meta之。保存的唯一时间戳是创建补丁/更改的时间(作者时间)和创建提交的时间(提交者时间)。
这是设计使然,因为Git是版本控制系统,而不是备份实用程序或同步工具。
更新:TL; DR:git本身不能保存原始时间,但是某些解决方案可以通过各种方法来避免这种情况。git-restore-mtime是其中之一:
https://github.com/MestreLion/git-tools/
Ubuntu / Debian:sudo apt install git-restore-mtime
Fedora / RHEL / CentOS:sudo yum install git-tools
查看我的其他答案以获取更多详细信息
完全免责声明:我是《 git-tools
这个python脚本可能会有所帮助:对于每个文件,在文件被修改时应用最新提交的时间戳:
下面是该脚本的一个非常简朴的版本。对于实际使用,我强烈建议您使用上述更强大的版本之一:
#!/usr/bin/env python
# Bare-bones version. Current dir 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不到4秒(24,000次提交,2,500个文件),Linux内核少于1分钟(40,000个文件,300,000次提交)
$ python ./git-restore-mtime Traceback (most recent call last): File "./git-restore-mtime", line 122, in <module> 'git rev-parse --show-toplevel --git-dir')).split('\n')[:2] TypeError: Type str doesn't support the buffer API您介意告诉我们需要什么版本的Python吗?我正在使用3.3.3
str在Python 2中等效bytestring于Python 3,而str在Python 3中等效unicode于Python2。您能否在github.com/MestreLion/git-tools/issues中报告此问题?
我已经使用git和file时间戳进行了一段时间的冲突。
测试了您的一些想法,并制作了我自己的巨大且前身/ ram繁重的脚本,直到我(在某些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;
假设您的存储库中没有超过10k个文件,这将需要几秒钟的时间来执行,因此您可以将其挂钩到checkout,pull或其他git基本挂钩。
这是我的解决方案,考虑了包含空格的路径:
#! /bin/bash
IFS=$'\n'
list_of_files=($(git ls-files | sort))
unset IFS
for file in "${list_of_files[@]}"; do
file_name=$(echo $file)
## When you collect the timestamps:
TIME=$(date -r "$file_name" -Ins)
## When you want to recover back the timestamps:
touch -m -d $TIME "$file_name"
done
请注意,这不会花费git log报告的时间,而是系统报告的时间。如果您需要自提交文件以来的时间,请使用git log解决方案,而不是date -r
本机git没有此功能,但可以通过挂钩脚本或第三方工具来实现。
我试过了metastore。它的速度非常快,但是我不喜欢安装的需求,并且元数据不是以纯文本格式存储的。git-cache-meta这是我尝试过的简单工具,但是对于大型存储库而言,它的运行速度非常慢(对于具有成千上万个文件的存储库,需要花费数分钟来更新元数据文件),并且可能存在跨平台兼容性问题。setgitperms其他方法也有我不喜欢的缺点。
最后,我为此工作制作了一个钩子脚本:git-store-meta。它具有很小的依赖性(* nix shellsort和perlgit是git所必需的,并且可选地chown是chgrpand touch),因此对于可以运行git的平台,不需要额外安装,性能令人满意(对于具有成千上万个回购协议的仓库的文件,更新元数据文件所需的时间不到10秒;尽管创建时间更长),以纯文本格式保存数据,并且可以自定义“保存”或“加载”的元数据。
对我来说效果很好。如果您对metastore,git-cache-meta和其他方法不满意,请尝试此操作。
我希望您欣赏它的简单性:
# 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
对于Windows环境,我在Delphi 10.1 Berlin中编写了一个小的(快速而肮脏的)EXE,它将源代码树中的所有文件日期收集到文件.gitfilattr中,然后可以将其再次应用到已检查的源代码树中。
当然,我在GitHub中共享代码:
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
我在基于GitLab运行程序的构建系统中使用了它。
使用GNU工具。
s=$(git ls-files | wc -l);
git ls-files -z |
xargs -0 -I{} -n1 bash -c \
"git log --date=format:%Y%m%d%H%M.%S '--pretty=format:touch -m -t %cd \"{}\"%n' -n1 -- {}"|
pv -l -s$s |
parallel -n1 -j8
967 0:00:05 [ 171 /s] [=====================================> ] 16%
。
$ git --version ; xargs --version | sed 1q ; ls --version | sed 1q;
parallel --version | sed 1q; pv --version | sed 1q; sh --version | sed 1q
git version 2.13.0
xargs (GNU findutils) 4.6.0
ls (GNU coreutils) 8.25
GNU parallel 20150522
pv 1.6.0 - Copyright 2015 Andrew Wood <andrew.wood@ivarch.com>
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
在CentOS 7中,您/usr/share/doc/rsync-*/support/git-set-file-times与Debian(及其衍生版本)中的脚本相同/usr/share/doc/rsync/scripts/git-set-file-times.gz,原始脚本来自Eric Wong,位于https://yhbt.net/git-set-file-times。
它的工作速度比这里提到的其他示例要快,您可能会发现将其安装在Linux发行版中更为方便。
这是我的。
比其他一些更快,因为我不会为找到的每个文件调用“获取日志”;而是一次调用“ git log”并将其输出转换为触摸命令。
在某些情况下,一次提交中列出的文件太多,无法容纳在单个shell命令缓冲区中。运行“ getconf ARG_MAX”以查看命令的最大长度(以字节为单位)-在我的debian安装中为2MB,足够了。
# set file last modification time to last commit of file
git log --reverse --date=iso --name-only | \
grep -vE "^(commit |Merge:|Author:| |^$)" | \
grep -B 1 "^[^D][^a][^t][^e][^:][^ ]" | \
grep -v "^\-\-" | \
sed "s|^\(.*\)$|\"\1\"|;s|^\"Date: *\(.*\)\"$|~touch -c -m -d'\1'|" | \
tr '~\n' '\n ' | \
sh -
按行描述:
就速度而言,它需要5秒1700提交700个目录中的6500个文件。