【问题标题】:Is there a syntax for referring to the commit which followed a commit in branch history?是否有引用分支历史中提交之后的提交的语法?
【发布时间】:2021-01-01 12:29:07
【问题描述】:

如果我有一个特定的哈希,将其命名为A,我可以通过A^ 找到父级。但是有没有办法获得分支历史中A 之后的提交?像A+1 这样的A(A+1)^?我想在我有哈希的那个之后检查提交,然后是之后的那个,依此类推,以检查它们。但他们真的被埋葬了。除了搜索 git log 输出之外,还有什么简单的方法可以在给定参考哈希的情况下检查它们?

【问题讨论】:

  • “A 之后的提交”没有单一的答案。单个提交可能是多个分支的一部分,并且可以有任意数量的提交跟随它。
  • 我认为是这样,但我希望有某种方法可以解决这个事实,比如“如果你将它限制在从 HEAD 到 A.... 的线性路径”假设应该可以使用简短的 bash 脚本,基本上从 HEAD 遍历父级,直到您点击 A。
  • 相关的,如果不是重复的话:stackoverflow.com/q/2263674/184546
  • A^ 是唯一的;它是提交 A 的 (a) 父级。可能有许多提交 B_i 这样 B_i^ == A

标签: git git-commit git-history


【解决方案1】:

我想在我有哈希的那个之后检查提交,然后是之后的那个,依此类推,以检查它们

git rev-list --first-parent --reverse $thathash..mybranch

将按顺序列出您想要签出的所有提交。如果您不仅想要线性历史记录,而且所有提交都来自分支提示历史记录中的该哈希,请将 --first-parent 替换为 --ancestry-path,您可以使用排序选项来决定访问它们的顺序。

【讨论】:

  • --first-parent 有个怪癖:如果$thathashmybranch 之间有两级合并,则来自$thathash 的第一级子提交将不会列在@987654328 中@ 列表。 --ancestry-path 是一个不错的选择(并且是内置的)
  • 我不会称其为怪癖,它源于“在分支历史中”的一个合法含义,也是唯一一个理解 OP 使用单数的含义,“A 之后的提交在分支历史中”。如果这就是 OP 的意思并且存在“两个级别的合并”,那么在“分支历史”中跟随 A 的唯一提交就是 --first-parent 将在此处列出。
【解决方案2】:

没有内置命令来查找两次提交之间的线性路径;您必须为此编写一个外部脚本。

这是一个例子,用 perl 编写(来自this answer):

# in file 'git-path.pl' :
#!/usr/bin/perl

use strict;
use warnings;

# This script implements a breadth first search, starting from $target,
# following the 'child -> parent' links, until $source is found or the
# complete history of $target is traversed.

my $source = $ARGV[0];
my $target = $ARGV[1];

my $srcsha = `git rev-parse -q --verify "$source"` || die "'$source' is not a valid source";
chomp($srcsha);
my $tgtsha = `git rev-parse -q --verify "$target"` || die "'$target' is not a valid target";
chomp($tgtsha);

# %seen stores the commits seen so far, linked to the child we are interested in
my %seen = ();
$seen{$tgtsha} = "";

# @stack lists the commits to visit
my @stack = ();
push @stack, $tgtsha;


# print_path : print the path from '$target' down to '$source'
sub print_path {
  my ($source) = @_;

  my @path = ();

  my $sha = $source;
  while ($sha) {
    unshift @path, $sha;
    $sha = $seen{$sha};
  }

  print "$_\n" for @path;
}


# main body :
# as long as there is something to scan, go for it,
# if $source is found along the way, print the path and exit with success
# otherwise, end the loop, and exit with failure

while( scalar(@stack) > 0 ) {
  my $sha = shift @stack;

  # extract parent lines from 'git cat-file -p commit'
  my @parents = `git cat-file -p $sha | grep '^parent ' | cut -c8-`;
  
  foreach my $p (@parents) {
    chomp($p);
    # for each parent, if not seen yet :
    #   * store it as a parent of $p
    #   * put it on the list of commits to explore next
    if (!$seen{$p}) {
      $seen{$p} = $sha;
      push @stack, $p;

      if ($p eq $srcsha) {
        # if we reached the 'source' commit : stop here
        print_path $p;
        exit 0;
      }
    }
  }
}

# no path found
exit 1;

示例用法:

$ perl git-path.pl A B
175015a5a00bbb9ad2ee4de23254ace4dbc645eb # commit B
bc03512e6082badab86a00cd320d89339741bb7b
077f584c10852cbadeef6c48886fd600cab61aa6
cec6734db31a1053b1b71674671512e1fe1592b1
b1dd3c71e42ca421f306640d4f0fdc69a00aa2c7
778a504c718f30d0dc2c72a30c885f10847f46a8 # commit A

【讨论】:

    猜你喜欢
    • 2017-09-11
    • 2011-11-08
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 2019-07-28
    • 2015-04-09
    • 2015-04-17
    相关资源
    最近更新 更多