简体   繁体   English

查找包含特定提交的合并提交

[英]Find merge commit which include a specific commit

Imagine the following history:想象一下以下历史:

       c---e---g--- feature
      /         \
-a---b---d---f---h--- master

How can I find when commit "c" has been merged into master (ie, find merge commit "h")?我如何找到提交“c”何时被合并到 master 中(即找到合并提交“h”)?

Your example shows that the branch feature is still available. 您的示例显示分支feature仍然可用。

In that case h is the last result of: 在这种情况下, h是以下各项的最后结果:

git log master ^feature --ancestry-path

If the branch feature is not available anymore, you can show the merge commits in the history line between c and master : 如果分支feature不再可用,则可以在cmaster之间的历史记录行中显示合并提交:

git log <SHA-1_for_c>..master --ancestry-path --merges

This will however also show all the merges that happened after h , and between e and g on feature . 但是,这也将显示在h之后以及eg之间在feature上发生的所有合并。


Comparing the result of the following commands: 比较以下命令的结果:

git rev-list <SHA-1_for_c>..master --ancestry-path

git rev-list <SHA-1_for_c>..master --first-parent

will give you the SHA-1 of h as the last row in common. 将为您提供h的SHA-1作为共同的最后一行。

If you have it available, you can use comm -1 -2 on these results. 如果可用,则可以在这些结果上使用comm -1 -2 If you are on msysgit, you can use the following perl code to compare: 如果您使用的是msysgit,则可以使用以下perl代码进行比较:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2

(perl code from http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , which took it from "someone at comp.unix.shell news group"). (来自http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/的 perl代码,来自“ comp.unix.shell新闻组的某人”)。

See process substitution if you want to make it a one-liner. 如果要使其成为单线,请参阅流程替代

Add this to your ~/.gitconfig : 将此添加到您的~/.gitconfig

[alias]
    find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
    show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"

Then you can use the aliases like this: 然后,您可以使用如下别名:

# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master

To see the merge commit's message and other details, use git show-merge with the same arguments. 要查看合并提交的消息和其他详细信息,请使用具有相同参数的git show-merge

(Based on Gauthier's answer . Thanks to Rosen Matev and javabrett for correcting a problem with sort .) (基于Gauthier的回答 。感谢Rosen Matevjavabrett纠正了sort的问题。)

git-get-merge will locate and show the merge commit you're looking for: git-get-merge将找到并显示您要查找的合并提交:

pip install git-get-merge
git get-merge <SHA-1>

The command follows the children of the given commit until a merge into another branch (presumably master) is found. 该命令遵循给定提交的子级,直到找到合并另一个分支(可能是主分支)为止。

That is, to summarize Gauthier's post: 也就是说,总结Gauthier的帖子:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' <(git rev-list --ancestry-path <SHA-1_for_c>..master) <(git rev-list --first-parent <SHA-1_for_c>..master) | tail -n 1

EDIT: because this uses process substitution " <() ", it is not POSIX compatible, and it may not work with your shell. 编辑:因为它使用进程替换<() ”,所以它与POSIX不兼容,并且可能不适用于您的Shell。 It works with bash or zsh though. 它适用于bashzsh

I needed to do this, and somehow found git-when-merged (which actually references this SO question, but Michael Haggerty never added a reference to his very nice Python script here). 我需要这样做,并且以某种方式找到了git-when-merged (实际上引用了这个SO问题,但是Michael Haggerty从未在这里添加对他非常漂亮的Python脚本的引用)。 So now I have. 所以现在我有。

Building on Gauthier's great answer, we don't need to use comm to compare the lists. 基于Gauthier的出色答案,我们不需要使用comm来比较列表。 Since we're looking for the last result in --ancestry-path which is also in --first-parent , we can simply grep for the latter in the output of the former: 由于我们正在--ancestry-path寻找最后一个结果,该结果也在--first-parent ,我们可以在前者的输出中为后者简单地grep:

git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1

Or for something snappy and reusable, here's a function to pop into .bashrc : 或为方便又可重复使用的功能,以下是弹出.bashrc的函数:

function git-find-merge() {
  git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}

For the Ruby crowd, there's git-whence . 对于Ruby人群,有git-whence Very easy. 很容易。

$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway

I use below bash script which I place at path ~/bin/git-find-merge . 我在下面的bash脚本中使用它放置在~/bin/git-find-merge路径中。 It's based on Gauthier's answer and evilstreak's answer with few tweaks to handle corner cases. 它基于 迪耶( Gauthier)的答案罪恶(evilstreak)的答案,并进行了一些调整以处理极端情况。 comm throws when the inputs are not sorted. 输入未排序时引发comm grep -f works perfectly. grep -f完美运行。

Corner cases: 角落案例:

  • If commit is a merge commit on first-parent path of branch, then return commit. 如果commit是分支的第一父级路径上的合并提交,则返回commit。
  • If commit is a NON-merge commit on first-parent path of branch, then return branch. 如果commit是分支的第一父级路径上的非合并提交,则返回branch。 It's either a ff merge or commit is only on branch and there is not a good way to figure out the right commit. 它要么是ff合并,要么是提交仅在分支上,并且没有一种很好的方法来找出正确的提交。
  • If commit and branch are same, then return commit. 如果commit和branch相同,则返回commit。

~/bin/git-find-merge script: ~/bin/git-find-merge脚本:

#!/bin/bash

commit=$1
if [ -z $commit ]; then
    echo 1>&2 "fatal: commit is required"
    exit 1
fi
commit=$(git rev-parse $commit)
branch=${2-@}

# if branch points to commit (both are same), then return commit
if [ $commit == $(git rev-parse $branch) ]; then
    git log -1 $commit
    exit
fi

# if commit is a merge commit on first-parent path of branch,
# then return commit
# if commit is a NON-merge commit on first-parent path of branch,
# then return branch as it's either a ff merge or commit is only on branch
# and there is not a good way to figure out the right commit
if [[ $(git log --first-parent --pretty='%P' $commit..$branch | \
    cut -d' ' -f1 | \
    grep $commit | wc -l) -eq 1 ]]; then
    if [ $(git show -s --format="%P" $commit | wc -w) -gt 1 ]; then
        # if commit is a merge commit
        git log -1 $commit
    else
        # if commit is a NON-merge commit
        echo 1>&2 ""
        echo 1>&2 "error: returning the branch commit (ff merge or commit only on branch)"
        echo 1>&2 ""
        git log -1 $branch
    fi
    exit
fi

# 1st common commit from bottom of first-parent and ancestry-path
merge=$(grep -f \
    <(git rev-list --first-parent  $commit..$branch) \
    <(git rev-list --ancestry-path $commit..$branch) \
        | tail -1)
if [ ! -z $merge ]; then
    git log -1 $merge
    exit
fi

# merge commit not found
echo 1>&2 "fatal: no merge commit found"
exit 1

Which lets me do this: 这让我做到了:

(master)
$ git find-merge <commit>    # to find when commit merged to current branch
$ git find-merge <branch>    # to find when branch merged to current branch
$ git find-merge <commit> pu # to find when commit merged to pu branch

This script is also available on my github . 这个脚本也可以在我的github上找到

My ruby version of @robinst's idea, works twice faster (which is important when searching for very old commit). 我的@robinst想法的红宝石版本工作速度提高了两倍(这对于搜索非常旧的提交非常重要)。

find-commit.rb

commit = ARGV[0]
master = ARGV[1] || 'origin/master'

unless commit
  puts "Usage: find-commit.rb commit [master-branch]"
  puts "Will show commit that merged <commit> into <master-branch>"
  exit 1
end

parents = `git rev-list #{commit}..#{master} --reverse --first-parent --merges`.split("\n")
ancestry = `git rev-list #{commit}..#{master} --reverse --ancestry-path --merges`.split("\n")
merge = (parents & ancestry)[0]

if merge
  system "git show #{merge}"
else
  puts "#{master} doesn't include #{commit}"
  exit 2
end

You can just use it like this: 您可以像这样使用它:

ruby find-commit.rb SHA master
git log --topo-order

然后在提交之前查找第一个合并。

This is the best way to find the commit in master:这是在 master 中查找提交的最佳方式:

[alias]
    find-merge = !"f() { git rev-list $1..master --ancestry-path --merges --reverse | head -1; }; f"

I've had to do this several times (thanks to everyone that answered this question!), and ended up writing a script (using Gauthier's method) that I could add to my little collection of git utilities. 我不得不做几次(感谢每个回答这个问题的人!),最后写了一个脚本(使用Gauthier的方法),可以将其添加到我的git实用程序的小集合中。 You can find it here: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point . 您可以在这里找到它: https : //github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point

A graphical solution is to find it in gitk (using the “SHA1 ID” box) and follow the line of commits up to the merge commit.图形解决方案是在gitk中找到它(使用“SHA1 ID”框)并按照提交行进行合并提交。

You can try something like this. 您可以尝试这样。 The idea is to iterate through all merge commit and see if the commit "c" is reachable from one of them: 这个想法是遍历所有合并提交,并查看其中的一个是否可以到达提交“ c”:

$ git log --merges --format='%h' master | while read mergecommit; do
  if git log --format='%h' $mergecommit|grep -q $c; then
    echo $mergecommit;
    break
  fi
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM