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 的代码。
问题:
现在或以后,我们如何将 Feature 1 / Commit #1 拉入 Master? (这样功能 1 和 2 都在 Master 中,并且历史在某种程度上是可以破译的,如果不是完全精简的话)
我说我们不能仅通过合并来做到这一点是否正确,因为 BEFORE_REVERTING_#1 只是指向同一节点的指针,该节点后来被还原,并且速度会很快已转发,需要使用其他一些 .git 功能?
如果您有幸了解 SourceTree UI - 有使用 SourceTree 的简单方法吗?
假设#1-3 已经发生,开发人员应该做什么,而不是步骤 4/5 中的方法?
感谢您提供的任何帮助或说明!
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")
上下文:
两个不同的功能被提交到同一个分支。最旧的提交代表一个内聚特性(“特性 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 的代码。
问题:
现在或以后,我们如何将 Feature 1 / Commit #1 拉入 Master? (这样功能 1 和 2 都在 Master 中,并且历史在某种程度上是可以破译的,如果不是完全精简的话)
我说我们不能仅通过合并来做到这一点是否正确,因为 BEFORE_REVERTING_#1 只是指向同一节点的指针,该节点后来被还原,并且速度会很快已转发,需要使用其他一些 .git 功能?
如果您有幸了解 SourceTree UI - 有使用 SourceTree 的简单方法吗?
假设#1-3 已经发生,开发人员应该做什么,而不是步骤 4/5 中的方法?
感谢您提供的任何帮助或说明!
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")