有没有办法知道或获取原始的创建/修改时间戳?感谢。
答案 0 :(得分:46)
是,metastore或git-cache-meta 可以存储此类(元)信息! Git本身,没有第三方工具,不能。 Metastore或git-cache-meta可以存储文件的任何文件元数据。
这是设计原因,因为metaore或git-cache-meta旨在用于此目的,并支持备份实用程序和同步工具。
(抱歉,雅库布的回答只是一点乐趣)
答案 1 :(得分:43)
我相信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
答案 2 :(得分:35)
否,Git只是 不存储此类(元)信息 ,除非您使用第三方工具,例如metastore或者git-cache-meta。存储的唯一时间戳是创建时间补丁/更改(作者时间),以及创建时间提交(提交者时间)。
这是设计,因为Git是版本控制系统,而不是备份实用程序或同步工具。
答案 3 :(得分:11)
这个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(24,000次提交,2,500个文件)不到4秒,linux内核不到1分钟(40,000个文件,300,000次提交)
答案 4 :(得分:5)
这对我来说就是ubuntu(在日期(1)上缺少OSX的“-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
答案 5 :(得分:3)
我已经用git和文件时间戳进行了一段时间的冲突。
测试了你的一些想法并制作了我自己非常庞大的前任/ 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基本挂钩。
答案 6 :(得分:1)
这是我的解决方案,它考虑了包含空格的路径:
#! /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
答案 7 :(得分:1)
原生git没有这个功能,但可以通过钩子脚本或第三方工具来实现。
我已经尝试metastore
了。它非常快,但我不喜欢安装的需要,并且元数据不是以纯文本格式存储的。 git-cache-meta
是我尝试过的一个简单工具,但对于大型回购而言速度极慢(对于拥有数万个文件的回购,更新元数据文件需要几分钟)并且可能有跨平台兼容性问题。 setgitperms
和其他方法也存在我不喜欢的缺点。
最后我为这份工作制作了一个钩子脚本:git-store-meta。它具有非常轻的依赖(* nix shell,sort
和perl
,这是git和chown
,chgrp
和touch
)因此,对于可运行git,理想性能的平台,不需要安装任何其他内容(对于包含数万个文件的repo,更新需要<10秒)元数据文件;虽然创建时间较长),但以纯文本格式保存数据,以及保存哪些元数据&#34;或者&#34;加载&#34; 可自定义。
它对我来说很好。如果您对metastore,git-cache-meta和其他方法不满意,请尝试此操作。
答案 8 :(得分:1)
我(以及其他人)对OP的解释是否意味着这意味着提交时间还是别的,但是假设它意味着提交时间,那么这个简单的单行将在linux中工作(基于答案片段)来自Dietrich Epp):
git ls-files | xargs -I{} bash -c 'touch "{}" --date=@$(git log -n1 --pretty=format:%ct -- "{}")'
但是从评论链接到cregox的原始问题还有更复杂的答案(包括git hooks)。
答案 9 :(得分:0)
对于Windows环境,我在Delphi 10.1 Berlin中编写了一个小的(快速且脏的)EXE,它将源树中的所有文件日期收集到文件.gitfilattr中,并可以再次在已检查的源代码树上应用它们。
当然我在GitHub中共享代码:
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
我在基于GitLab跑步者的构建系统中使用它。
答案 10 :(得分:0)
使用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)
答案 11 :(得分:0)
我希望您欣赏它的简单性:
# 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 don't 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
答案 12 :(得分:0)
在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发行版中更为方便。
答案 13 :(得分:0)
这是我的。
比其他一些更快,因为我不为找到的每个文件调用“获取日志”;而是一次调用“ 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个文件。
答案 14 :(得分:0)
for file in `find . -type f -not -path "./.git/*"`; do
touch -d "`git rev-list -n 1 HEAD \$file | xargs git show -s --format=%ai`" $file;
done