重新设置公共分支

Dro*_*ror 8 version-control git

我无法理解如何使用git-rebase,我考虑了以下示例。

让我们在 中启动一个存储库~/tmp/repo

$ git init
Run Code Online (Sandbox Code Playgroud)

然后添加一个文件 foo

$ echo "hello world" > foo
Run Code Online (Sandbox Code Playgroud)

然后添加并提交:

$ git add foo
$ git commit -m "Added foo"
Run Code Online (Sandbox Code Playgroud)

接下来,我启动了一个远程存储库。在~/tmp/bare.git我跑

$ git init --bare
Run Code Online (Sandbox Code Playgroud)

为了链接repobare.git我跑了

$ git remote add origin ../bare.git/
$ git push --set-upstream origin master
Run Code Online (Sandbox Code Playgroud)

接下来,让我们分支,添加一个文件并为新分支设置一个上游b1

$ git checkout -b b1
$ echo "bar" > foo2
$ git add foo2
$ git commit -m "add foo2 in b1"
$ git push --set-upstream origin b1
Run Code Online (Sandbox Code Playgroud)

现在是时候切换回master并更改那里的内容了:

$ echo "change foo" > foo
$ git commit -a -m "changed foo in master"
$ git push
Run Code Online (Sandbox Code Playgroud)

此时master文件中foo包含已更改的 foo,而b1其中仍然是hello world。最后,我想b1master.

$ git checkout b1
$ git fetch origin
$ git rebase origin/master
Run Code Online (Sandbox Code Playgroud)

此时git st返回:

# On branch b1
# Your branch and 'origin/b1' have diverged,
# and have 2 and 1 different commit each, respectively.
#   (use "git pull" to merge the remote branch into yours)
#
nothing to commit, working directory clean
Run Code Online (Sandbox Code Playgroud)

此时foo分支中的内容b1也是change foo。那么这个警告是什么意思呢?我希望我应该做一个git push,git 建议做git pull...根据这个答案,这或多或少是这样,并且在他的评论中@FrerichRaabe 明确表示我不需要拉。这里发生了什么?有什么危险,应该如何处理?历史应该如何保持一致?上述案例与以下引用之间的相互作用是什么:

不要将您推送到公共存储库的提交变基。

取自pro git book

我想这在某种程度上是相关的,如果不是,我很想知道为什么。上述场景与我在这篇文章中描述的程序之间有什么关系。

hea*_*vyd 8

您不想重新设置已推送到公共存储库的提交的原因是因为该git-rebase命令更改了历史记录。

现在,这是什么意思,为什么不好?首先,我建议阅读Git 书的这一部分。从中您将了解到提交由指向树对象(文件的快照)的指针和指向父提交的指针组成。现在,当您通过在新提交之上重新提交提交来“更改历史记录”时,您正在更改已提交的父指针,这反过来又更改了提交的 id。

这很糟糕的原因是,如果你公开分享你的提交,而其他人根据这些提交开始额外的工作,那么你去更改这些提交,你的树不再同步。

您可以通过git-log在执行示例时发出一些命令来查看所有这些。我在运行 rebase 命令之前运行了这些:

$ git log --pretty=oneline origin/master
9b077261d1619803213201d5c7cefb757eb66b67 Changed foo in master
911ce5b247e79682ec9f73ad9a15fd3167b7e76d Added foo

$ git log --pretty=oneline origin/b1
63a57ef54e301314a9dab38de0cd9d88c59a5fba added foo2 in b1
911ce5b247e79682ec9f73ad9a15fd3167b7e76d Added foo

$ git log --pretty=oneline b1
63a57ef54e301314a9dab38de0cd9d88c59a5fba added foo2 in b1
911ce5b247e79682ec9f73ad9a15fd3167b7e76d Added foo
Run Code Online (Sandbox Code Playgroud)

现在在执行 rebase 之后,origin/masterorigin/b1是一样的,但b1现在是:

$ git log --pretty=oneline b1
6687c64c37db0ee21a4d87e45d6ccb0913b8686d added foo2 in b1
9b077261d1619803213201d5c7cefb757eb66b67 Changed foo in master
911ce5b247e79682ec9f73ad9a15fd3167b7e76d Added foo
Run Code Online (Sandbox Code Playgroud)

您会注意到“在 b1 中添加了 foo2”提交的 ID 与之前的日志命令中的 ID 不同。如果您将此更改提交到您的公共存储库,则您现在有两个提交,它们在其中完成了相同的工作,并且会导致问题。

现在假设,您只是将 master 合并到 b1 中,而不是在 master 之上重新设置 b1,您的日志将如下所示:

$ git checkout b1
$ git merge origin/master
$ git log --pretty=oneline b1
518eb2dc6b2da0ff43ddd6837332031cc00eaad1 Merge remote-tracking branch 'origin/master' into b1
9b077261d1619803213201d5c7cefb757eb66b67 Changed foo in master
63a57ef54e301314a9dab38de0cd9d88c59a5fba added foo2 in b1
911ce5b247e79682ec9f73ad9a15fd3167b7e76d Added foo
Run Code Online (Sandbox Code Playgroud)

您会注意到额外的提交,它代表了前两个提交的合并。现在可以分享这段历史,每个人都会很高兴。

git-log --graph 还可以帮助了解正在发生的事情。