小编典典

如何更新 fork 以发出干净的拉取请求?

all

我正在为github上的分叉副本上的开源 repo 做出贡献

我通常只修复我发现的奇怪的错误,所以每隔几个月就会发生一次,同时还会发生许多其他的开发。我在我的 fork 中提出了拉取请求以获取新的更改。

现在它们出现在我的拉取请求中,返回到原始仓库在此处输入图像描述

如何制作仅包含每个修复提交的干净拉取请求?我曾尝试 git 在本地获取原始仓库并从中进行合并,但我遇到了同样的问题。


阅读 152

收藏
2022-03-11

共1个答案

小编典典

tl; dr:从上游/主分支分支。不要向当地的主人承诺。

如果您的分支有本地更改并且您只是与上游合并,那么您仍然会有这些本地更改。当你基于这个合并的 master 提交 PR 时,它将包含那些本地更改。

让我们演示一下。这是与本地更改合并后的样子。

# Your situation after merging with local changes.
# D - E - F are new changes from upstream.
# 1 - 2 - 3 is your local changes.

A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]

现在你从 master 创建一个分支并添加一些提交。

A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]
                       \
                        4 - 5 - 6 [feature]

如果您将 feature 作为 PR 提交,以 upstream/master 作为基础,它将拖入 1 - 2 - 3 以及 4 - 5 - 6,因为它们都包含与 upstream/master 的差异。

这就是为什么要避免直接提交到 master,你不再有新分支的共同基础。相反,在分支中完成所有工作并将它们作为 PR 提交。


最简单和最安全的事情是将您的工作从上游/master 分支而不是 master。那么你的分叉处于什么状态并不重要。

$ git checkout -b feature upstream/master
# then make a few commits

                      4 - 5 - 6 [feature]
                     /
A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]

如果您有一个现有的 master 分支,请将其 rebase 到 upstream/master。这将重写每个提交,就像您在上游/主控之上编写它一样。可能存在冲突,根据需要修复它们。

# Before with feature based on master.

A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]
                       \
                        4 - 5 - 6 [feature]

# Rebase onto upstream/master the commits from master to feature.
$ git rebase --onto upstream/master master feature

                      4A - 5A - 6A [feature]
                     /
A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]
                       \
                        4 - 5 - 6

原来的 4 - 5 - 6 最终会被删除。


要恢复 fork 的 master,请将您的 master 返回master给上游的 master。

首先,在您现有的 master 上创建一个新分支以保留任何本地更改。

$ git checkout master
$ git branch dev  # or whatever you want to call it

A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [master]
                        [dev]

现在,您对 master 所做的任何本地更改都将保留在您的dev分支中。您可以随意称呼它,但要避免使用上游已经存在的分支名称。

然后将您的本地主机移动到上游的主机。

$ git checkout master
$ git reset --hard upstream/master

                      [master]
A - B - C - D - E - F [upstream/master]
         \           \
          1 - 2 - 3 - M [dev]

Git 中的分支只是指向提交的标签。git reset是您如何随心所欲地移动它们。这会将您的本地主机移动到上游/主机指向的位置。--hard指对暂存区和签出文件(工作副本)做什么。--hard说还要将它们重置为上游/主控。

现在你的主人是他们的上游/主人。dev 对 master 进行了本地更改。

最后,将新的本地 master 推送到 origin。既然搬了,就不得不强行。不要使用 –force使用更安全的git push --force-with-lease.

如果你想更新你的本地 master,只需git pull. Agit pull只是一个git fetch加号git merge。我们将做git pull两个单独的步骤来演示。

# Fetch new commits, that's G and H.
$ git fetch upstream

                      G - H [upstream/master]
                     /
A - B - C - D - E - F [master]
         \           \
          1 - 2 - 3 - M [dev]

$ git checkout master
$ git merge upstream/master

                            [master]
                      G - H [upstream/master]
                     /
A - B - C - D - E - F
         \           \
          1 - 2 - 3 - M [dev]

由于 master 是 upstream/master 的直接祖先,因此不需要合并提交。Git 将“快进”master 到上游/master。

2022-03-11