Git:合并分支但保留提交历史

19

在我的git工作流中,我们有一个主要的代码库和一个名为master的分支。每个人都从远程的master分支拉取代码并将代码推送到远程的master分支。当我准备开发一个新功能时,我想在自己的分支上工作。目前为止,我的版本历史记录大致如下:

git pull --rebase
git checkout -b new_feature
<make some commits>
git checkout master
git pull --rebase

现在我想要合并分支,以下是我需要的:

  1. 我的本地主分支中没有合并提交。
  2. 将所有在新功能分支上进行的提交合并到主分支中,就好像我是在主分支上进行了这些提交。
  3. 所有已经合并的提交都会被合并到本地远程头指针的某个位置上面。

我最担心的是第三点,在安全推送更改之前需要做什么。如果已经合并的提交与头部之前的提交交织在一起,那么我将无法推送,参见我遇到的相关问题:git: Pushing Single Commits, Reordering with rebase, Duplicate Commits

我已经阅读了以下内容:

我认为我需要执行以下操作:

git checkout master
git pull --rebase
git checkout new_feature
git rebase master
git checkout master
git rebase new_feature
git push

我的理解是:

git checkout new_feature
git rebase master

将使新功能看起来像是从新的当前主干分支出来的。这是真的吗?

git checkout master
git rebase new_feature

将 new_feature 置于 master 之上。这样正确吗?如果是这样,那么这就是我困惑的主要问题。如果 "git rebase master" 将 master 的提交置于 new_feature 底部,那么为什么 "git rebase new_feature" 将 new_feature 的提交置于 master 顶部,即为什么它不相反呢?

2个回答

29

答案

这里有一个工作流程,您可以使用它来做您需要的事情。

git checkout master
git pull --rebase                             (1)
git checkout new_feature                      
<do a bunch of commits>
git rebase master                             (2)
git checkout master
git merge new_feature                         (3)
git branch -D new_feature                     (4)

说明

(1) git pull --rebase 会首先获取 origin/master,然后将本地的 master 分支应用在它之上。请注意,在示例日志中,你的本地提交记录是基于你的 "本地远程 HEAD 指针"的顶部。

> git log --oneline --all -10 --decorate

d34d34c (HEAD, master) Local commit message.
d3434r2 Local commit message.
d234d4c Local commit message.
er3ede3 (origin/master, origin/HEAD) Remote commit message.
sfe3fd3 Remote commit message.

你现在可以 checkout 并在你的 new_feature 分支上工作一段时间。完成后...

(2) git rebase master 将会把 new_feature 重新应用到 master 上。同样,你本地的提交记录将会保持在 "local remote HEAD pointer" 的顶部。

> git log --oneline --all -10 --decorate

fc5773d (new_feature) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c (HEAD, master) Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

rebase 命令只是将 new_feature 分支放在了主分支(master)之前,为了使它们对齐,需要运行...

(3) git merge new_feature,这会执行一个快进合并(fast-forward merge)。现在,HEADnew_featuremaster 都指向同一个提交。

> git log --oneline --all -10 --decorate

fc5773d (HEAD, new_feature, master) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

(4) 在此之后,您可以安全地删除new_feature分支。在推送之前,您的最终日志将如下所示:

> git log --oneline --all -10 --decorate

fc5773d (HEAD, master) Local new_feature commit 2
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

1
非常好的答案!我认为“git checkout new_feature”需要 -b 标志(除非分支已经存在)。你引用了我的“本地远程 HEAD 指针”的用法,什么是正确的术语? - Samuel
@Samuel 是的。除非 new_feature 分支已经存在,否则您需要使用 -b 选项。 - Shaun Luttin
1
@Samuel 我会使用“远程HEAD引用”而不是“本地远程HEAD指针”。请参见http://www.git-scm.com/book/en/v2/Git-Internals-Git-References页面底部。 - Shaun Luttin

6
在新功能分支上运行git rebase master之后,在主分支上运行git rebase new_feature是不必要的。在新功能分支上运行git rebase master之后,您可以将其合并到主分支中 - 这将是一个快进合并,不会引入合并提交。 git rebase new-feature不能将所有新功能提交放在主分支之上的原因是,git已经认识到主分支已经是新特性的基础 - 我们使用git rebase master执行了这一步骤 - 并且它只会快速前进到新特性。
另外,您不需要担心推送位于远程/master顶部以下的提交 - 如果您尝试(除非提供-f选项,否则)远程将拒绝您的推送。如果您的本地主分支正在跟踪您的远程主分支,则git status将告诉您本地是否已与远程分支分歧。

很棒的答案,快进合并是关键。谢谢! - Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接