是否可以在Git存储库的初始状态下检索一组文件
我有一个git存储库,其中包含许多(是否可以在Git存储库的初始状态下检索一组文件,git,initialization,commit,Git,Initialization,Commit,我有一个git存储库,其中包含许多(.tex)文件,这些文件是在不同的时间/提交时添加的。我想将它们复制到一个临时目录中,因为它们处于初始状态(当它们被添加到存储库时)。重点是在做一些工作之前,向某人展示他们有多丑:) 有可能吗?您应该在首次将提交添加到存储库时首先找到提交,为此,您可以运行: git log <PATH_TO_YOUR_FILES> | tail 现在,您可以通过运行以下命令获得提交中的文件: git cat-file -p 4adbcaf:<PATH_TO
.tex
)文件,这些文件是在不同的时间/提交时添加的。我想将它们复制到一个临时目录中,因为它们处于初始状态(当它们被添加到存储库时)。重点是在做一些工作之前,向某人展示他们有多丑:)
有可能吗?您应该在首次将提交添加到存储库时首先找到提交,为此,您可以运行:
git log <PATH_TO_YOUR_FILES> | tail
现在,您可以通过运行以下命令获得提交中的文件:
git cat-file -p 4adbcaf:<PATH_TO_YOUR_FILE>
保存脚本并运行它:
git-restore-initial-state.sh file_a file_b
编辑:感谢他在简化脚本方面的帮助。当然有可能,但在完成时,您可能希望您只是选择了几个样本进行手动提取 因此,首先,您需要确定“文件的第一个版本”。我能想到的最简单的方法是使用
git log
——这对于脚本编写来说不是很好,但是
git log --diff-filter=A --name-only --format=' :COMMIT: %H' --all -- *.tex **/*.tex
格式字符串以您合理预期的文件路径以外的内容开头。我在末尾添加了一些pathspec参数,这将限制输出仅显示.tex
文件。这可能是两种方法中效率更高的一种;但如果它引起问题,我会在下面的脚本中提到一个替代方案
现在您有了一个提交列表。对于每个提交,您都会看到提交ID(哈希),后面是在提交中创建的文件列表
因此,您可以使用您喜欢的任何类型的脚本来处理该输出。我使用perl来处理这类事情,所以
my $sha = 0;
while(<>) {
chomp;
next if m/^$/;
if ( m/^ :COMMIT: ([0-9a-f]*)$/ ) {
$sha = $1;
} else {
system("git --work-tree=/path/to/temp/dir checkout $sha -- $_");
}
}
如果希望在perl脚本中包含git log
命令,则如下所示:
# git-restore-initial-state.sh
#!/bin/bash
mkdir -p temp
for f in "$@"
do
commit=$(git log --pretty=%H "$f" | tail -1)
git cat-file -p "$commit:$f" > "temp/$f"
done
my $sha = 0;
while(<>) {
chomp;
next if m/^$/;
if ( m/^ :COMMIT: ([0-9a-f]*)$/ ) {
$sha = $1;
} elsif ( m/\.tex$/ ) {
system("git --work-tree=/path/to/temp/dir checkout $sha -- $_");
}
}
my $sha = 0;
my @list = `git log --diff-filter=A --name-only --format=' :COMMIT: %H' --all -- *.tex **/*.tex`;
foreach(@list) {
chomp;
next if m/^$/;
if ( m/^ :COMMIT: ([0-9a-f]*)$/ ) {
$sha = $1;
} elsif ( m/\.tex$/ ) {
system("git --work-tree=/path/to/temp/dir checkout $sha -- $_");
}
}
要获取每个文件的第一个提交ID/desc(带“.tex”): 您可以使用以下方法查看初始提交完整消息:
for f in *.tex; do git show $(git log --oneline "$f" | tail -1 | awk '{print$1}'); done
要在临时目录中复制初始文件,可以使用下一个脚本:
$ mkdir ../temp
$ ls *.tex > ../temp/listOfFiles.txt
$ cat ../temp/listOfFiles.txt | while read line; do git checkout $(git log --oneline "$line" | tail -1 | awk '{print$1}'); cp "$line" ../temp/"$line"; git checkout master; done
$ git status
最后,回购处于最后状态。。希望这有帮助。这就是如何将其中一个复制到工作树的方法。OP询问了一种将所有这些文件复制到临时目录的方法。用这种方法挑选一些样本可能会更好地利用时间,但实际上并不能解决问题question@MarkAdelsberger谢谢Mark,我明白你的意思了,用一个脚本编辑,它可以恢复一组文件,复制到临时目录并将其恢复到其头部state@MahdiDibaiee我可以给你一些建议来改进你的剧本吗
git log--pretty=%H--path_to_file
可以获取更改此文件的所有提交git cat file-p commit:path_to_file
可以打印提交文件的内容。因此,您可以使用这两个命令简化脚本。git cat file-p“$commit:$f”>“temp/$f”
命令导致错误fatal:不是有效的对象名⟨承诺⟩:⟨档案⟩
@DenisBitouzé您能分享一下您执行的确切命令吗?可能有助于调试脚本。我已经在虚拟存储库上测试过它,但可能是一个边缘案例。另一方面,您是否尝试手动查找文件的提交以查看是否成功?我在temp
目录中获得的文件与Git存储库中的当前版本相同。我刚刚完成了第二次测试,目前运行良好。。确保您的回购在第一个代码中更新,我想%H
之后的后引号应该是(正常)引号。除此之外,您的解决方案似乎有效,但不幸的是,它捕获了太多的文件:我想将其仅限于.tex
文件。修复了引号,并添加了一些选项以过滤非.tex
文件。效果很好。如果将所有内容都收集到Perl脚本中,而不是在第一个命令上管道化,则会更好:)
for f in *.tex; do git show $(git log --oneline "$f" | tail -1 | awk '{print$1}'); done
$ mkdir ../temp
$ ls *.tex > ../temp/listOfFiles.txt
$ cat ../temp/listOfFiles.txt | while read line; do git checkout $(git log --oneline "$line" | tail -1 | awk '{print$1}'); cp "$line" ../temp/"$line"; git checkout master; done
$ git status