13

我有本地masterdevelop分支机构。我完成所有工作develop,然后将它们合并到master发布中。有一个远程分支,upstream/master其中有我想要的更改,但我想在develop其更改之上重新调整我的更改(共享一个共同的祖先)并将它们放回develop. 我已经完成了git fetch upstream

关于变基的Git 书籍章节说要做:

$ git checkout experiment
$ git rebase master

我(假设)在我的情况下意味着:

$ git checkout upstream/master
$ git rebase develop

但那时我会upsteam/master处于分离的头部状态。但是,如果我合并了upstream/master,我会从 开始develop,并且更改将在 上develop,例如

$ git checkout develop
$ git merge upstream/master

所以这种变基的方式对我来说似乎是倒退的。我想将我的更改重新设置在develop分支develop上,这些更改upstream/master类似于合并的工作方式。我是否应该在 上进行变基upstream/master,修复任何冲突,然后添加它,将其隐藏并将其弹出到 上develop

4

3 回答 3

16

变基实际上是:

git checkout develop
git rebase upstream/master

git rebase应该阅读:“在目标分支的顶部develop,这里重新设置我当前的分支,这里”)upstream/master

最终的结果不会是一个分离的头,而是新改写的develop分支。

于 2013-10-05T17:48:49.990 回答
14

最简单(对每个人来说最明显)的方法是首先更新您的master分支,然后重新设置到更新的基础上master,这与现在完全相同origin/master

$ git fetch origin                    # Get updates from remote.
$ git checkout master                 # Now bring master into sync:
$ git merge --ff-only origin/master   # if this fails you have stuff
                                      # in your master that they don't
                                      # have in theirs, and you need
                                      # to decide what to do about it

在这一点上,如果一切顺利,master并且origin/master都是相同的(如您可以通过图形查看器看到的gitk,或使用git log --graph --oneline --decorate),那么应该很清楚git rebase master将如何工作。

但你实际上不必这样做。你可以只是git rebase origin/master,而正在上develop。(这将使您的master未转发 - 大概在某些时候您会希望它转发 - 所以它并没有真正为您节省太多。但现在容易做到。)


冗长乏味的“为什么”部分:git rebase在其长篇中包含三点,文档将其描述为newbaseupstreambranch

git rebase ... [--onto <newbase>] [<upstream>] [<branch>]

如果您只指定一个参数,如 in git rebase master,则命名 theupstream和 bothnewbasebranch计算。是当前branch分支(即,HEAD不能分离)。如果省略--onto,则将newbase作为upstream参数。因此,如果您现在在运行,develop并且运行git rebase X,则branchisdevelop和 bothnewbaseupstreamare X

rebase 方法实际上是(有各种内部优化,对 reflog 的影响有点不同):

  1. 查看branch
  2. 保存ORIG_HEAD对提交的引用 ( ) 指向branch哪个
  3. 将它(a la git reset --hard)重置为newbase
  4. 对于upstream..ORIG_HEAD1中的每个提交(按最旧到最新的顺序),git cherry-pick该提交将其添加到刚刚重置的分支。

因此,如文档中所述:

   Assume the following history exists and the current branch is "topic":

                 A---B---C  HEAD=topic
                /
           D---E---F---G    master

git rebase master你得到:

                   A---B---C         ORIG_HEAD
                  /
                 /       A'--B'--C'  HEAD=topic
                /       /
           D---E---F---G             master

(我在这里所做的只是以手册页中的示例并添加ORIG_HEAD标签和HEAD=,以表明原始提交“仍在其中”,这HEAD是对 的引用topic)。

那么,如果你有你的develop并且master他们有他们的master其中有一些额外的变化,会发生什么?让我们画出:

A -- B -- C                         master
          | \
          |   D                     origin/master
          |
          E -- F                    HEAD=develop

现在你git rebase origin/master

A -- B -- C                         master
          | \
          |   D                     origin/master
          |     \
          |       E' -- F'          HEAD=develop
          |
          E -- F                    ORIG_HEAD

在某些时候,您最终也将自己master的指向提交D(并且您放弃ORIG_HEAD)给予:

A -- B -- C -- D                    master, origin/master
                 \
                   E' - F'          HEAD=develop

这与一些标签移动的情况相同。

这就是分支标签的全部内容,它们只是标签。每个标签指向一个(单个)提交。提交本身指向以前的提交,这是构建提交树(或“提交 DAG”,实际上)的内容。


1语法隐藏了很多“深奥的魔法”。它的意思是“所有可以从标签到达但不能从标签到达的提交。这正是需要精心挑选的一组提交,因为那些是在“变基”操作之前打开和未打开的提交. 乍一看,它“看起来像”一个基于时间的序列,这通常在人们的脑海中起作用,但它基于提交图拓扑。有时这会让人们绊倒: repo 中的多个提交树),表示“每个版本都可以从.Git's X..YYXbranchupstreamA..BABB

于 2013-10-05T18:11:55.400 回答
1

您正在寻找的命令是:

git checkout develop
git rebase upstream/master

但是,Git 比这更聪明,您可以将 upstream/master 配置为开发的上游跟踪分支:

git branch --set-upstream-to upstream/master develop

现在,当你这样做时git rebase,它会自动使用'upstream/master'。但更好的是,这些命令:

git fetch origin
git rebase upstream/master

可以通过简单地简化:

git pull --rebase
于 2013-10-06T01:36:47.930 回答