当一个模块被分割成两个较小的文件时,如何更好地合并git中的更改?

问题描述 投票:0回答:1

我厌倦了 python god 模块,并将其分解为两个较小的模块,除了将函数/对象拉出来并将它们放入更具逻辑意义的文件中之外,重构也很有限。 不幸的是,这足以混淆 git 通常的合并逻辑,因为它认为第一个文件已被删除,并且添加了两个全新的文件。 现在,每当我必须合并 main 时,我都不会得到有用的合并,而是得到三个文件并被告知找出它们有何不同。

有没有办法获得更有用的合并,以显示原始文件和两个较小文件之间发生了什么变化?

git git-merge
1个回答
0
投票

有没有办法获得更有用的合并,以显示原始文件和两个较小文件之间发生了什么变化?

是的。作为示例内容,我使用了 Onat Korucu 的 this answer 中的代码,它是一个 Java 文件 (

LoginManager.java
),然后分成多个较小的文件(其中包括
DecryptHandler.java
)。

最初的一个文件内容被签入分支

one_file
,最重要的是,文件被分割成多个文件的新提交被签入分支
multiple_files
。之后,
one_file
分支已更新,用一些虚拟代码替换其中一个函数的 TODO 主体。

接下来的挑战是将此更新从

one_file
分支引入/合并到
multiple_files
分支。只是尝试将
one_file
合并到
multiple_files
失败了,就像您所描述的那样。

让 git 执行此操作的关键是分多个步骤执行此操作,并为每个步骤使用单独的分支。对于原始文件分割成的每个文件,需要分别重复这些步骤,例如在你的情况下两次。

第一步是将原始文件重命名为文件分割的目标之一,例如在我的例子中

DecryptHandler.java
。我创建了一个分支
intermediate/DecryptHandler/filename
为此(即在此分支上
DecryptHandler.java
现在与原始
LoginManager.java
相同)。

第二步是使用

multiple_files
分支的内容更新重命名的文件,以便
DecryptHandler.java
现在在两个分支上相同。我为此创建了一个分支
intermediate/DecryptHandler/content

历史现在看起来像这样:

gitk

Gitk screenshot 1

第三步是将来自

one_file
的更新合并到文件名分支中。由于这个分支只是重命名,所以 git 没有任何问题,并且合并也没有任何问题。

第四步现在是将更新的

intermediate/DecryptHandler/filename
分支合并到
intermediate/DecryptHandler/content
分支中(注意,不是相反)。这次 git 将因冲突而放弃,但这只是正常的合并冲突,其中 git 记录了同一文件名的所有三个贡献版本,并且使用 KDiff3 轻而易举,KDiff3 自动解决了所有问题。

此时,我可以将

intermediate/DecryptHandler/content
合并到
multiple_files
中,然后就到此为止(因为我只有一个更改影响一个文件。当您有两个文件时,您可能需要对另一个文件重复操作)。

历史在

gitk
中看起来像这样:

Gitk screenshot 2

然而,这将提供有问题的提交的历史记录,这些提交会破坏

git bisect
git test
等,因此最好“合并”结果而不实际将其记录为合并。这可以通过实际合并完成的分支中的
git diff ... | git apply -
来完成。

所以第五步是合并到

multiple_files
以外的分支,但具有相同的提交。

git branch intermediate/DecryptHandler/merge multiple_files
git switch intermediate/DecryptHandler/merge
git merge intermediate/DecryptHandler/content
# Conflict because same file added independently on two branches.
# Simple to resolve with KDiff3 and it is clear that we want the B version.
git resolve-conflict-using-kdiff3
git commit

第六步是复制合并提交而不合并:

git switch multiple_files
git diff multiple_files intermediate/DecryptHandler/merge | git apply -
git add DecryptHandler.java
git commit -m "Stealth merge of one_file branch" -m "git diff multiple_files intermediate/DecryptHandler/merge | git apply -"

现在给出了一个

multiple_files
分支,它通过一些中间步骤“合并”了
one_file
中的内容。

历史现在看起来像这样:

gitk

Gitk screenshot 3


现在,历史记录看起来有点嘈杂,很可能您希望在更新完成后排除那些中间分支的显示1。通过提供

--exclude=...
选项可以很简单地做到这一点。每次启动
gitk
时手动指定都太麻烦了,因此假设您有一个名为
gitkall
的包装脚本,用于
gitk --all
将其更新为以下内容:

#!/bin/sh

exec gitk \
        "--exclude=refs/notes/*" \
        "--exclude=refs/heads/hide/*" \
        "--exclude=refs/heads/intermediate/*" \
        --all \
        "$@" &

忽略注释是针对

git test
保存的测试结果,我想隐藏所有名称以“hide/”开头的分支。第三个排除是忽略此答案中的中间分支。 (这里的顺序很重要,--exclude 选项必须位于--all 之前)。

用这个启动 gitk 将给出一个更简单的视图:

Gitk screenshot 4


1此时您也可以删除它们,但是下次您想要进行更改时需要重新创建它们。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.