找到补丁适用的第一个或最后一个提交

时间:2014-05-28 05:19:13

标签: git patch git-patch git-bisect git-apply

假设补丁是从过去的特定提交创建的,不再适用于HEAD。

如何在HEAD历史记录中找到第一个或更好的最后一次提交,此修补程序适用于“git apply”? 也许git bisect的东西?但是哪个命令会告诉我补丁是否适用?

理想情况下,我想回到该提交,应用补丁,然后重新绑定或与原始HEAD合并,再次diff以创建新补丁,除非发生冲突。 在此之后,我想回到最初的HEAD,所以我可以继续使用更多的补丁。

背景:有许多补丁需要重新加载...... (是的,有生态系统补丁仍然是一个东西..)

2 个答案:

答案 0 :(得分:2)

此答案假定修补程序是使用git diff创建的,而不是git format-patch,并且git log的默认寻呼机为less

以下是从git diff <sha1> <sha2>

创建的补丁示例
diff --git a/osx/.bash_profile b/osx/.bash_profile
index c7b41df..fb80367 100644
--- a/osx/.bash_profile
+++ b/osx/.bash_profile
@@ -3,6 +3,10 @@
 # Setup PATH for Homebrew packages
 export PATH=/usr/local/bin:$PATH

+# Setup Scala variables
+export SCALA_HOME=/usr/local/Frameworks/scala # Symlinked directory
+export PATH=$PATH:$SCALA_HOME/bin
+
 # Initialize rbenv,
 # https://github.com/sstephenson/rbenv#homebrew-on-mac-os-x
 eval "$(rbenv init -)"

采取这一行:

+export SCALA_HOME=/usr/local/Frameworks/scala # Symlinked directory

并在git log --patchgit log -p中搜索。在/中输入less,然后输入您要搜索的正则表达式:

/\+export SCALA_HOME=/usr/local/Frameworks/scala # Symlinked directory

此处+使用\进行转义,因为它是正则表达式中的特殊字符。按Enter键查找第一个匹配项,然后按n调出下一个匹配项,或N进入上一个匹配项。

这将帮助您找到可能适用于修补程序来源的提交。您还可以使用less中的空格键向下翻页,并b进行翻页。

答案 1 :(得分:1)

git希望您执行此操作的方式

git apply --3way应该使用blob哈希定位每个文件的基本版本,并一步一步合并所有文件,假设它们存在于您的回购历史记录中,并且您可以处理合并冲突。对于许多人来说,这可能是一个更简单的解决方案。

您要做什么的方式

如果您仍然真的想知道包含diff的基本文件的历史提交,则下面的脚本将locate commits containing a single blob hash的解决方案之一扩展为尝试查找包含从中提取的一组blob哈希值的提交补丁文件。

#!/bin/sh
# git-find-patch-base takes a patch produced by "git diff" and tries to locate commit(s)
# containing all source blobs

# The first parameter is the name of the patch file to examine
patch_file="$1"
# Any remaining parameters are passed as a group to the git log command using $@ below
shift

# Make a temporary file and capture a list of all the starting
# file blob hashes that the patch used in it. Note: Adding a file shows
# a starting hash of 00000000, so we filter that one out...
tmp_blob_file=$(mktemp)
echo "Examining patch file \"$patch_file\"..." 1>&2
grep -E "^index" "$patch_file" | colrm 1 6 | colrm 10 | sort | uniq | grep -v 00000000 > "$tmp_blob_file"

# Count how many unique blob hashes we identified
blobcount=$(cat "$tmp_blob_file" | wc -l)
echo "Found $blobcount unique blob hashes in patch..." 1>&2

# Use git log to get a list of commits to check against. Then, for
# each of those commits, count how many of the blob hashes that we
# wanted appear in it, and output the commit hash if it's at least the
# ideal blob count. Note: this is an imperfect searching method, since
# there is a chance for hash collision, exacerbated since the grep is not
# forcing the short hashes to only match the beginning of the long
# hashes.
echo "Searching log/tree history of git..." 1>&2
git log "$@" --pretty=format:'%T %h %s' \
| while read tree commit subject ; do
    if test $(git ls-tree -r "$tree" | grep -f "$tmp_blob_file" | wc -l) -ge "$blobcount" ; then
        echo "$commit" "$subject"
        break
    fi
done

# Clean up the temporary file we made...
rm "$tmp_blob_file"

第一个参数是要分析的补丁文件的名称,所有剩余参数都传递给git log,以帮助扩展/限制要检查的提交列表。如果要相对于特定分支进行第一次提交,则可以运行git-find-patch-base foo.patch branchname。如果您完全不知道某物来自何处,则可以运行git-find-patch-base foo.patch --all,然后边喝咖啡边做。 git日志上有很多有用的限制器,例如--grep--author,可以加快此过程。

所示脚本在第一次循环中停止,而break在while循环之外。您可以删除它,它将彻底搜索所有内容,并吐出所有候选提交。