GIT 工作流程:将大部分功能分支合并到主分支中,省略一个特定的提交?

GIT Workflow: Merge most of a feature branch into master, omitting one specific commit?

上下文:

两个不同的功能被提交到同一个分支。最旧的提交代表一个内聚特性(“特性 1”)。所有后续提交都代表第二个独立的内聚功能(“功能 2”)。

回想起来,这些应该是独立的功能分支,但它们都提交到同一个分支。

问题:

现在:预料中的问题出现了。开发人员被要求将功能 2 合并到主控中,但不是功能 1。

他们做了什么:

#0 他们从 MASTER 分支出来,打算将该分支用于功能 2 - 称他们的新分支为“Feature_2”。

#1 他们忘记了他们在哪个分支上(功能 2),并且 make/test/commit/push 在一次提交中为“功能 1”加载大量文件更改。

#2, 3, 4 然后他们继续对功能 2 进行所有必要的更改,同时提交和推送到同一个分支。

现在 - 有人要求他们在没有功能 1(提交 #1)的情况下提交功能 2(提交 #2、#3、#4)。

#4 他们创建了一个新分支并将其命名为“BEFORE_REVERTING_#1”

#5 他们 Git 还原提交 #1(通过 sourcetree 的 'reverse changes...' 选项。)

#6 他们将 commit#5 合并到 master 中。

最终状态:

所以现在他们已经成功地将 #2、3、4 合并到 master 中,而无需来自 #1 的代码。

问题:

感谢您提供的任何帮助或说明!

Now or later, how do we pull Feature 1 / Commit #1 into Master?

Cherry pick吧。本质上,这会复制提交。

git checkout master
git cherry-pick <commit id of feature 1>

What should the dev have done, instead of the approach in step 4/5, assuming #1-3 had already happened?

还原提交没问题。但他们也可以将功能分支拆分为两个分支。

你有这个。

A - B [master]
     \
      1A - 2A - 2B [feature]

你想要这个。

      2A - 2B [feature]
     /
A - B [master]
     \
      1A [feature1]

首先,在1A上贴一个新的分支。

git branch feature1 1A

A - B [master]
     \
      1A [feature1]
        \
         2A - 2B [feature]

然后在 master 之上对 2A 和 2B 进行 rebase。

git rebase --onto master 1A 2B

      2A1 - 2B1 [feature]
     /
A - B [master]
     \
      1A [feature1]

大功告成。


对于更复杂的理清,使用 interactive rebase 有选择地去除 提交。例如,如果您有...

A - B [master]
     \
      1A - 2A - 1B - 2B [feature]

而你想要...

      2A - 2B [feature]
     /
A - B [master]
     \
      1A - 1B [feature1]

feature 创建一个新分支。

git checkout feature
git branch feature1

A - B [master]
     \
      1A - 2A - 1B - 2B [feature]
                        [feature1]

然后对它们中的每一个进行交互式变基。删除有问题的提交。从 feature 中删除 1A 和 1B。从 feature1 删除 2A 和 2B。

git checkout feature
git rebase -i master
# delete 1A and 1B

      2A - 2B [feature]
     /
A - B [master]
     \
      1A - 2A - 1B - 2B [feature1]
git checkout feature1
git rebase -i master
# delete 2A and 2B

      2A - 2B [feature]
     /
A - B [master]
     \
      1A - 1B [feature1]

择优选择(根据 Schwern 的回答)可能是最简单的解决方案;但请务必考虑 team/project 的分支策略。您可能希望挑选一个新的 feature 1 分支并将其合并到 master,而不是直接挑选到 master。

有多种其他方法可以复制由于还原而被排除在 master(或其他分支)之外的提交,具体取决于具体情况。如果整个分支已被排除(因为它被合并并且合并被恢复),检查分支和 rebase -f 通常是有意义的。主要区别在于,如果你这样做,你将用新的提交重写分支历史(除非你专门使用不这样做的过程);在挽救整个分支的情况下,这可能是您想要的,但您需要注意重写分支的含义,如果它已被共享。

我不同意其他答案的地方是,开发人员所做的 可能会或可能不会 是 "fine"。这取决于您的团队就如何使用 git 达成的协议。这可能看起来很挑剔,但我真的厌倦了 "experts" 在 slashdot 上告诉团队他们的工作协议应该是什么样子,只是因为这是他们习惯做事的方式。

一般来说,开发人员有两个选择:他们可以从 feature 2 分支恢复提交——他们可能做了最直接的变体——代价是必须稍后复制恢复的提交并有一个"weird" 历史。或者他们可以重写历史以分离分支,代价可能是对所有开发人员进行一些分支清理,因为这意味着重写已经共享的分支的历史(请参阅他们谈论的 git rebase 文档"upstream rebase")