当我使用“git clone ...
”命令克隆Git存储库时,本地存储库中的所有克隆文件都具有相同的修改时间,日期和时间与发出git clone
命令时相同。
是否有一种方法可以克隆远程Git存储库,并为每个文件使用实际修改时间?
Git 不记录文件的时间戳, 因为它是一种分布式版本控制系统(意味着您计算机上的时间可能与我的不同:没有“中央”时间和日期的概念)
不记录元数据的官方论据在这个答案中解释。
但是,您可以找到脚本,尝试恢复有意义的日期,(或者同样思路的简化版本)。
git ls-tree -r --name-only HEAD | while read filename; do
unixtime=$(git log -1 --format="%at" -- "${filename}")
touchtime=$(date -d @$unixtime +'%Y%m%d%H%M.%S')
touch -t ${touchtime} "${filename}"
done
同时请参阅我在此处的要点。
Makefile
的构建过程。 - Erik Osterman有另一种重置 mtime 的选项是git-restore-mtime。
sudo apt install git-restore-mtime # Debian/Ubuntu example
git clone <myurl>
cd <mydir>
git restore-mtime
git ls-files -z | xargs -0 -n1 -I{} -- git log -1 --format="%ai {}" {} | perl -ne 'chomp;next if(/'"'"'/);($d,$f)=(/(^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d(?: \+\d\d\d\d|)) (.*)/);print "d=$d f=$f\n"; `touch -d "$d" '"'"'$f'"'"'`;'
(也可以是
)的文件。也许您可以找时间查看这些特定情况? - user7468395以下是我认为更易于理解的user11882487的答案的简短版本:
git ls-files | xargs -I{} git log -1 --date=format:%Y%m%d%H%M.%S --format='touch -t %ad "{}"' "{}" | $SHELL
在一行代码列表中添加...
for f in $(git ls-files) ; do touch -d $(git log -1 --format='%aI' "$f") "$f" ; done
log -1
一次只能处理一个文件,这让我感到很烦。因此,我编写了这个程序可以一次性处理所有文件。( # don't alter any modified-file stamps:
git diff --name-status --no-find-copies --no-renames | awk '$1="D"' FS=$'\t' OFS=$'\t'
git log --pretty=%cI --first-parent --name-status -m --no-find-copies --no-renames
) | awk ' NF==1 { date=$1 }
NF<2 || seen[$2]++ { next }
$1!="D" { print "touch -d",date,$2 }' FS=$'\t'
这个命令可以在十秒钟内完成 Linux 历史记录的操作(将所有的 touch 命令通过 shell 进行管道传输需要一分钟)。
这是破坏二分法等操作的好方法。我属于那些认为不要试图超负荷使用文件系统时间戳的阵营,坚持这样做的人显然必须经过艰苦的学习,但我可以看出,在某些工作流中,这可能真的不会对你造成伤害。
总之,千万不要盲目地这样做。
git ls-files
的输出(而不是使用xargs)?“每个文件运行一次log -1”这个答案指的是哪些答案(有四个答案都有“log -1”)?(使用链接到答案,因为用户名可能随时更改。) - Peter Mortensenlog -1
的答案必然会对每个文件运行一次,我的反对是针对这种方法的。 - jthill这适用于以前多个答案中的解决方案:
使用%at
格式,然后使用touch -d \@$epochdelta
,以避免日期时间转换问题。
在Python中实现这一点比其他选项要简单,因为os.utime
接受git log
命令输出的Unix时间戳。这个示例使用了GitPython,但也可以使用subprocess.run
调用git log
来实现。
import git
from os import utime
from pathlib import Path
repo_path = "my_repo"
repo = git.Repo(repo_path)
for n in repo.tree().list_traverse():
filepath = Path(repo.working_dir) / n.path
unixtime = repo.git.log(
"-1", "--format='%at'", "--", n.path
).strip("'")
if not unixtime.isnumeric():
raise ValueError(
f"git log gave non-numeric timestamp {unixtime} for {n.path}"
)
utime(filepath, times=(int(unixtime), int(unixtime)))
这与此答案中的git restore-mtime
命令和最高评分答案中的脚本结果相匹配。
如果您在克隆后立即执行此操作,则可以重用传递给git.Repo.clone_from
的to_path
参数,而不是访问Repo
对象上的working_dir
属性。
git ls-tree -r --name-only HEAD | ForEach-Object { "$(git log -1 --format="%ai" -- "$_")`t$_" } | sort
git log -n1 -- file
命令获取文件最后修改的时间;这也是git
的作用之一。 - Amadan