14

我们使用 git 来管理我们应用的代码仓库,有一个我还没有遇到过的情况,但我想是很常见的。

我们想暂时删除一个功能,然后在将来的某个时候重新添加它。我试图想象支持这一点的分支结构,或者我们是否应该做一些简单的事情,比如从代码中删除该功能,并在准备重新添加它时,从提交历史中重新创建它。

谁能指出我处理这种情况的正确方向?

4

4 回答 4

11

您可以暂时删除在 Git 存储库历史之前的功能的一种方法是进行提交以删除该功能。然后,当您想重新添加该功能时,只需还原将其取出的提交。这将做一个反向补丁,这意味着它将反向应用更改,这将有效地重新添加该功能:

git revert <sha of commit that removed the feature>

如果您想确保以后可以轻松地重新添加该功能,同时使其与对代码的更改保持同步,您可以在删除它后立即创建一个单独的功能分支,然后只处理该分支像任何其他功能分支一样,并通过频繁地对其master(或develop分支,如果这是您想要的方式)重新定位来保持同步,随时解决冲突。

所以基本上,你会想做这样的事情(如果你使用GitHub FlowGit Flow分支策略并不重要,两者都使用最终合并到主线的功能分支的概念开发。为简单起见,我将在此示例中使用 GitHub Flow):

# On master branch
git commit -m "Remove feature X" # Creates commit 1234567...

# Now make feature branch
git checkout -b saved-feature

# Immediately put the feature back in the feature branch
git revert 1234567

# When you want to sync branch with master, just use rebase.
# Rebase allows you to sync frequently, since it doesn't
# leave behind a bunch of merge commits.
#
# From the feature branch:
git rebase master # Resolve any conflicts as needed.

# N commits later, you decide it's time to merge the feature
# back in.  You can use fast-forward or non-fast-forward merge,
# it's up to you.
#
# Using fast-forward merge with master checked out (assuming
# feature branch was just rebased onto master):
git merge saved-feature

# Or forcing a merge commit, if that's what you want:
git merge --no-ff saved-feature

假设您saved-feature经常与master(或者develop,如果您使用的是)保持同步,并在进行中解决冲突,那么重新合并该功能应该没有问题。

参考文档:

于 2013-07-10T03:56:22.330 回答
2

这是一个应该奏效的策略。听起来你的工作已经融入了你的项目,所以这就是我要做的。首先选择你的起点,对我来说通常是dev分支(假设还有一个master branch)。分拆新分支,该分支将是从您的项目中删除的功能

git checkout -b dev_feature_removed

同时旋转一个分支,该分支将是项目中维护的那个特性。

git checkout -b dev_feature_sustained

现在进行编码和测试,您需要确保此功能已正确且完全删除dev_feature_removed,一旦您确定是这种情况,将该分支重新合并到生产环境中。在我的情况下,开发以进行进一步测试,然后进入 master 上线。

同时,您也可以将其他分支保留dev_feature_sustained在您的仓库中。您可以将 dev 合并到此分支中以使其保持同步,还可以添加到已删除的功能(错误修复或新的花里胡哨)中,以便通过将其合并回 dev(在我的情况下可能是您的主)。

此功能的返回可能会导致合并冲突,具体取决于您的功能的紧密耦合程度。由于你的早于回购,听起来你无论如何都会产生冲突,因为合并策略只能做这么多。但是,由于您将拥有两棵完整的提交树,一棵带有该功能,另一棵没有,您将知道您的功能重新连接到您的项目的每个点的存在。因此,您将拥有将其放回项目中所需的一切。这就是我将在我的情况下起草的内容。祝你好运,伙计。

于 2013-07-10T00:11:46.830 回答
2

这是一个具体示例,显示了John Galt 回答中的策略:

$ git log --graph --decorate --oneline
*   d1d201b (HEAD, restore-b) Merge branch 'prod' into restore-b
|\
| * 18d759f (prod) add feature e in prod
* |   191037e Merge branch 'prod' into restore-b
|\ \
| |/
| * e0de1be add feature d in production
* | a122936 Revert "remove feature b in production"
|/
* d3e2c42 remove feature b in production
* 5369ecf existing three features

基本上,restore-b总是包含所有内容prod以及功能的恢复(提交a122936)。当您在 上进行新提交时prod,它们会被合并到restore-b中,因此无论何时您准备好恢复该功能,它都是一个简单的快速合并。

一种更简单的方法是避免创建a112936提交和restore-b分支,直到您准备好恢复该功能。创建和更新restore-b分支的好处是,与其他更改的任何冲突都可以及时解决(希望在编写冲突代码后不久由编写冲突代码的开发人员解决)。这使功能保持“新鲜”和“现成”,准备好包含在生产版本中,而无需额外的开发工作。

于 2013-07-10T03:39:11.450 回答
0

我会在代码本身中解决这个问题。添加一个功能映射(基本上是每个功能的布尔标志),然后根据需要启用/禁用功能,而无需实际从存储库中删除代码/逻辑。

配置文件中的内容很简单,例如:

<?php
$features = array(
    'news' => true,
    'events' => true,
    'shop' => false
);

然后在您相应的控制器中:

<?php
class ShopController extends AbstractController {

    public function __construct() {
        // $features array would be passed in somehow;
        // maybe via a dependency injection container
        if (!$features['shop']) {
            // feature is disabled, so just send 404 page for now
            throw new ResourceNotFoundException();
        }
    }
}

注意:以上是半伪代码。

于 2013-07-10T00:16:54.750 回答