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 上创建一个新分支以保留任何本地更改。
$ 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 分支中。你可以随意命名它,但要避免使用上游已经存在的分支名称。
然后将本地 master 移动到上游的 master。
$ 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。
如果您想更新本地主机,只需git pull。 git 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 到 upstream/master。