Git适用于上午

时间:2017-08-02 16:03:36

标签: git

我使用以下命令生成了补丁

git log -p -m -1 --pretty=email --first-parent XXXX

我想将此修补程序应用于另一个存储库(具有相同的文件但不一定具有相同的历史记录)。

使用git apply时,正确应用了补丁,但我必须自己使用正确的用户提交文件,日期......

使用git am时出现以下错误:

  

错误:toto.cpp:补丁不适用

我只是无法理解为什么它可以与apply一起使用但不能与am

一起使用

知道如何将其应用于am

编辑: 链接答案中给出的答案只是解释applyam期间不会提交更改。更多内容表示am在后​​台使用apply,因此它似乎是am命令特有的失败。

1 个答案:

答案 0 :(得分:4)

git am命令故意挑剔其输入格式,以便它可以创建一个新的提交,其哈希ID 的哈希ID相同原始提交,这反过来意味着git am创建的新提交与原始提交一点一点地相同。

git apply命令故意对其输入格式不那么挑剔,因为而不是git apply会创建一个不<的新提交/ em>与任何原始提交完全相同。

您的问题从命令开始:

git log -p -m -1 --pretty=email --first-parent

表示您正在显示合并。 git format-patch命令从不在其输出中包含合并,因为git am无法进行合并。由于git am的要点是进行逐位相同的提交,而git format-patch的要点是产生适合输入git amgit am的输出,进行合并,git format-patch不需要提交合并提交。

这些结合使git am工具无法用于您的特定目的(似乎将合并提交转换为针对其第一个父级的变更集,通过电子邮件传输变更集或类似于电子邮件,然后在另一端应用它以获得具有相似但不相同的元数据的不同提交,就像通过cherry-pick )。您只需编写自己的工具,或使用git apply并手动提交。

如上段所示,您可以使用一种编写自己的工具的方法是在合并的第一个父级(可能在分离的HEAD上)选择合并(使用-m 1),使用git format-patch格式化该修补程序,并使用git am将该修补程序应用于其他位置。这个脚本很不经过测试,但可能有效:

#! /bin/sh

. $(git --exec-path)/git-sh-setup

# abort if on orphan branch (not worth the necessary hackery)
git rev-parse -q --verify HEAD 2>/dev/null ||
    die 'this does not work on an orphan branch'

# stolen out of git-filter-branch
finish_ident() {
    # Ensure non-empty id name.
    echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac"
    # And make sure everything is exported.
    echo "export GIT_$1_NAME"
    echo "export GIT_$1_EMAIL"
    echo "export GIT_$1_DATE"
}

set_ident () {
    parse_ident_from_commit author AUTHOR committer COMMITTER
    finish_ident AUTHOR
    finish_ident COMMITTER
}

# begin format-patch-even-if-merge code

hash=$(git rev-parse --verify "$1") || exit # verify that it's valid
hash=$(git rev-parse $hash^{commit}) || exit # and that it's a commit
parents=$(git rev-parse $hash^@)
set $parents

# if a root commit or ordinary commit, just use git format-patch
case $# in
0|1) git format-patch --stdout -1 $1; exit;;
*) ;; # merge - use cherry-pick
esac

# this is the meat of the trick, here
firstparent=$1
exec 3>&1 1>&2 # save stdout and redirect to stderr

echo "cherry picking $hash onto $firstparent to make it format-able"

# save where we were (branch or hash); arrange to return
# there on exit or ^C etc
if ! returnto=$(git symbolic-ref --short HEAD 2>/dev/null); then
    # already detached, save hash ID
    returnto=$(git rev-parse HEAD)
fi
trap "git checkout $returnto; exit" 0 1 2 3 15

# Use the identity of the merge creator for new commits.
# NOTE: this should be optional and probably NOT the default,
# so it is commented out here.
#eval "$(set_ident <$hash)" ||
#    die "setting author/committer failed for commit $hash"

# Move to a detached head on the first parent of the merge.
git checkout $firstparent || exit

# Now we can cherry-pick the merge to a non-merge.
git cherry-pick -m 1 $hash || exit

# Now show the commit we just made, to original stdout.
git format-patch --stdout -1 HEAD 1>&3

还有一些注意事项,仅仅是为了完整性

如果您希望完整地传输合并提交,那么通过标准git pushgit fetch协议可以轻松实现。如果由于某种原因不可用,git bundle命令可以创建一个文件(Git称之为 bundle ),其中包含跨越障碍传输存储库的某些部分所需的所有数据推/获取本身不能交叉。然后,您可以在捆绑文件上运行git fetch,以便在以其他方式跨越该障碍后提取必要的信息。

但是,请注意,您需要 all 从合并提交中可以访问的对象:bundle必须包含 other Git 缺少的每个对象。 fetch和push命令的重点是让 Git 计算这组对象:两个Gits相互通信,找出接收Git缺少的发送Git的含义。那是什么进入了捆绑。虽然捆绑包有额外的对象(接收Git可以忽略它们)是正常的,但是传输它们是浪费资源,因此获取或推送将计算最小化对象设置,将其打包成一个&#34;薄包&#34; (捆绑的fetch / push等价物),通过线路发送,让另一端解压缩。