繁体   English   中英

Git:从上游变基到开发分支

[英]Git: rebase onto development branch from upstream

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

关于 rebaseGit 书籍章节说要这样做:

$ 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上做 rebase,修复任何冲突,然后添加它,把它藏起来,然后把它弹出到develop吗?

变基实际上是:

git checkout develop
git rebase upstream/master

git rebase应该读作:“rebase 我当前的分支,这里是develop目标分支之上,这里是upstream/master ”)

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

最简单(对每个人来说最明显)的方法是首先更新你的master分支,然后 rebase 到更新的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

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

但实际上您不必这样做。 你可以在developgit rebase origin/master (这将使你的master在某些点未进-ED-想必你会希望它前进-ED-所以它不是真正的节省您很多,但是它现在更容易做。)


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

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

如果您只指定一个参数,如在git rebase master ,则命名upstream并且计算newbasebranch branch是当前分支(即HEAD ,不得分离)。 如果省略--onto ,则将newbase作为upstream参数。 因此,如果您现在正在develop ,并且您运行git rebase X ,则branchdevelop并且newbaseupstream都是X

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

  1. 签出branch
  2. 保存对branch指向的提交的引用( ORIG_HEAD
  3. 将它(a la git reset --hardgit reset --hardnewbase
  4. 对于upstream ..ORIG_HEAD 1 中的每个提交(按从旧到新的顺序), 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的引用)。

那么,如果你有你的developmaster而他们的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也指向 commit D (并且您删除ORIG_HEAD )给出:

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

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

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


1 Git's X .. Y语法隐藏了很多“深奥的魔法”。 这意味着“所有提交都可以从标签Y到达,但不能从标签X到达。这正是需要挑选的提交集,因为那些是在branch上的提交,而不是在upstream ,在“rebase”操作。乍一看,它“看起来像”一个基于时间的序列,这通常在人们的A..B ,但它基于提交图拓扑。但有时这会让人绊倒: A..B ,其中A根本与B无关(因为 repo 中有多个提交树),意味着“可以从B访问每个修订版。

您正在寻找的命令是:

git checkout develop
git rebase upstream/master

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

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

现在,当您执行git rebase ,它会自动使用“上游/主”。 但更好的是,这些命令:

git fetch origin
git rebase upstream/master

可以通过简单地执行以下操作来简化:

git pull --rebase

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM