【问题标题】:matching tarball to a git repository将 tarball 与 git 存储库匹配
【发布时间】:2020-08-08 10:53:49
【问题描述】:

给定一个 git 存储库和一个没有修订信息的 tarball。 tarball 中的树在过去的某个时间点源自存储库,并且发生了相当大的变化。存储库也发生了很大变化。从存储库复制 tarball 树的提交是未知的。任务是找到最接近 tarball 的提交,检查 tarball 树中的更改或将 tarball 树嫁接回存储库。

我之前通过手动二分搜索做到了这一点,最大限度地减少了diff -ruN gitrepo tartree | wc -c 的输出。我想知道是否有可以自动执行任务的工具?

【问题讨论】:

  • 如果 tarball 树在最初创建后发生了变化,我看不到任何可以确定找到原始提交的方法。但是您可以将它应用于历史中的每个提交,并查看您从提交的内容中获得最少更改的地方。一旦你找到了修改最少的提交,你可能已经有了它的提交,但不能保证。
  • 蛮力可以作为一种解决方案来找到与你的 tar 球相比具有最小差异的提交。但是如果你对所做的修改没有任何线索,你必须定义一个度量来定义最接近的。顺便说一句,没有什么能保证最接近的是原始提交

标签: git merge branch


【解决方案1】:

感谢 fredrikÔrel 的 cmets。我知道原始提交可能会或可能不会被发现,所以我说“最接近”。我编写了一个线性蛮力搜索,它确实找到了一个很好的极值,比我之前做的手动考虑要快得多......特别是如果你猜得很好从哪个提交开始搜索。

(更新:根据LeGEC 的建议,使用git log --pretty=format 缩短了脚本)。

#!/usr/bin/perl

# Estimate similarity of $DIR to every commit in ```git log``` output,
# output a line for every commit.  ```git log``` starts from the
# currently checked out commit and goes back in time.
#
# The script is quick and dirty: it checks out every commit in turn to
# take a diff.  After the script stops for whatever reason, the last
# commit seen stays checked out.  You will have to restore the original
# checkout yourself.

sub usage {
    die ("Usage:\n",
         "  cd clean-git-repo\n",
         "  git-match-dir DIR\n");
}

sub main {
    my $dir = $ARGV[0] // usage();
    open (my $fh, "git log --pretty='%H %ad'|") or die;
    while (<$fh>) {
        # d2e9457319bff7326d5162b47dd4891c652c2089 Thu Sep 14 09:44:58 2017 +0300
        my ($commit, $date) = /(\w+) \w\w\w (.*)/;
        $commit or die "unexpected output from git log: $_";
        my $out = `git checkout $commit 2>&1`;
        $? == 0 or die "$out\nCheckout error.  Stop";
        my $len = 0 + `diff -wruN --exclude .git . $dir | wc -c`;
        printf("%10u %s %s\n", $len, $commit, $date);
    }
}

main();
exit 0;

【讨论】:

  • 看看git help log中的漂亮格式:解析git log --pretty=format:"%H %(ad)"会更容易
  • 使用 Perl,解析行结构文本是轻而易举的事。但事实上,如果我知道 --pretty=format,它可能会更简单。谢谢!
  • 如果它是用 Lisp 编写的,我了解宇宙的机会就会少得多......很高兴听到它是 Perl :)
【解决方案2】:

如果 tarball 是您的一个 repo 提交的确切内容,您可以搜索树哈希:

  1. 使用 git 计算 tarball 树的哈希
  2. 打印commit-hash tree-hash的列表
  3. grep 1. in 2.

  1. 在一个空目录中:
  • 创建一个仓库
  • 解压压缩包
  • 运行git add -a &amp;&amp; git commit
  • 运行git rev-parse HEAD^{tree}
  1. 在你的 git 仓库中,运行:

    git log --all --pretty=format:"%H %T"

  2. grep 1. 在 2 生成的列表中的输出。

【讨论】:

  • 不幸的是,这不会像我的情况一样,repo 和 tarball 树都已被修改。我们必须松散地匹配,而不是严格地匹配。
  • 压缩包不是从过去的提交中生成的吗?
  • 您可以扫描子树的哈希,例如:将git rev-parse tarball:src/some/modulegit rev-parse commit:src/some/module 匹配
  • 您的 diff 方法也很有效。查找已计算的哈希值比在每次提交时运行完整的 checkout + diff 更快。
  • 即使 repo 和树中的每个文件都不同,Diff 也会处理。散列不会,即使极端(在每次提交中为每个文件生成散列)
猜你喜欢
  • 1970-01-01
  • 2012-11-20
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多