10

我在源代码管理中出现了一个相当罕见的问题。在此处的示例中,Perforce 出现了问题,但我怀疑许多 SCM 也会出现同样的问题,尤其是分布式 SCM。

Perforce 支持更改列表(或更改集,如果您愿意)。变更列表支持两种常见用法:

  1. 当您提交更改列表时,提交是原子的,因此所有文件都已提交或没有。这是大多数人在提到变更列表时谈论的标题功能。

  2. Perforce 支持多个更改列表。基本上,当您签出一个文件时,您会告诉它它属于哪个更改列表。因此,如果您正在开发花哨的新电子邮件功能,这将需要数月的工作并赚取数百万美元,并且技术支持人员向您提出必须在昨天修复的错误,您不必从整个项目的一个新分支。您可以将有缺陷的文件签出到新的更改列表中,修复问题,签入新的更改列表,然后回到新电子邮件功能的实际工作中,就好像什么都没发生一样。

在大多数情况下,一切都很好。但是,当您实现电子邮件功能时,您会在所有地方进行无数次更改,尤其是在 main.h 中,而碰巧的是,当您开始修复错误时,您会发现必须进行的微小更改也在main.h中。新功能的更改列表已经签出了 main.h,因此您不能轻易将其放入更改列表中以进行错误修复。

现在你做什么?你有几个选择:

  1. 创建一个新的客户端规范。Perforce 中的 clientspec 是 depot 中的文件/目录列表以及要复制所有内容的本地目的地。因此,您可以创建项目的第二个副本,而无需对电子邮件功能进行任何更改。

  2. 做一个软糖。备份您修改后的 main.h 副本并恢复此文件。然后,您可以自由地将 main.h 检出到错误修复更改列表中。您修复错误,签入错误修复更改列表,然后将 main.h 签入电子邮件功能更改列表。最后,您从一开始所做的备份中合并所有更改。

  3. 您确定您对 main.h 所做的所有更改都没有副作用或依赖性,因此您只需将 main.h 移到错误修复更改列表中,进行更改并将其签入。然后您再次将其签出到电子邮件功能中更改列表。显然,这种方法有两个问题:首先,实际上可能存在您没有考虑过的副作用,其次您已经破坏了您的版本历史。

选项 1 可能是最干净的,但并不总是实用的。我正在处理的一个项目有数百万行代码和一个非常复杂的构建过程。设置一个新环境需要一天的时间,所以 5 分钟的 bug 修复是不切实际的。

选项 3 是一个糟糕的选项,但它是最快的,所以它可能非常诱人。

这留下了选项 2,这是我通常会使用的选项。

有人有更好的解决方案吗?

对于这个冗长的问题,我深表歉意,但我在 StackOverflow 上发现,经过深思熟虑的问题可以得到更好的答案。

4

8 回答 8

7

这个确切的问题被称为“纠结的工作副本问题”。Ryan Tomayko 有一篇名为The Thing About Git的博客文章详细讨论了这个问题以及 Git 如何解决它。

这是关于 Git 的最好的事情之一。我git add -p至少每天都使用,以帮助提交彼此独立的有意义的单独代码块。两个逻辑上不同的更改在同一个源文件中的事实已变得无关紧要。

于 2009-01-16T06:14:59.717 回答
3

我通过从一开始就维护多个工作区来使用 Perforce 进行管理。我的主要开发在主线上(发生新开发的地方),而另一个则指向已发布代码的分支。如果我需要修复一个错误,我会去发布分支。

我不确定这是否适合您,但至少您不需要在每次修复错误时都创建新工作区(因为它已经存在)。

于 2009-01-19T20:20:13.197 回答
2

ClearCase 还支持变更列表(在其 UCM 风格中称为“活动”),并提出了类似的挑战。

仅当您确定“调试工作”与当前的开发工作(电子邮件功能)不兼容并且最好将其保存在单独的分支中时,选项 1(“分支类型”)才有意义。然后,您可以将“补丁”分支中所做的任何更正改进到主分支(因为并非您要修复的每个错误都必须存在于两者中:当前的开发可能已经使某些修复过时)。
另请参阅“什么是分支”,以及您的合并工作流程是什么。

选项 3 说明了变更集概念的限制:文件的单个修订(或“版本”)一次只能是一个变更集的一部分。

Greg 提到git add -p(添加补丁)是选项 1 和 3 的替代,因为它利用了“索引”(暂存区)的暂存功能,您可以在该区域中决定实际提交的内容以及保留的内容在你的私人空间。 这很好,但根据我的经验,在很长一段时间内很难维持,特别是在一组常见的文件上,你应用了两种不同的演变。分支更干净,更易于单元测试。但是,对于您提到的小修复,这可能是一个不错的出路。

当您意识到您对两种不同的努力有两个更改时,选项 2 是实用的解决方案(它们仍然兼容,不会相互“破坏”)。
但可能是一个更简单的解决方案是:

  • 在电子邮件中检查 main.h 的当前状态,
  • 签出错误,修复它,签入错误
  • 然后在电子邮件中结帐以恢复电子邮件功能开发。

同样,如果这两个开发工作(电子邮件和错误)是兼容的,您可以拥有包含混合活动的修订历史记录。

于 2009-01-16T06:54:18.530 回答
2

我们使用作业,以便单个“任务”可以跨越多个提交的变更集。

所以:

  1. 检查 main.h 更改是否独立于其他更改
  2. 签入 main.h 的当前状态 - 在长期电子邮件工作中
  3. 对 main.h 进行错误修复
  4. 签入错误修复变更集
  5. 如果需要,在电子邮件作业下编辑 main.h
于 2009-01-16T12:11:14.127 回答
2

您没有提到选项 4,即创建分支。

您可以拥有不进行任何单独更改的主代码行 - 只是来自其他分支的集成。

然后你就有了主要的开发线,你可以在其中创建你喜欢的新电子邮件功能。这是你做大部分工作的地方。

最后你有你的错误修复分支。这是您进行所有小修改和紧急错误修复的地方。一旦这些经过测试,它们就会被集成到 QA 和发布的主代码行中(应该在一个单独的分支上)。然后可以将这些编辑从主线集成到您的开发线中,以便您始终使用最新的代码。这种集成可以在您选择的时间发生 - 这样您就可以确信它不会在您的新代码中造成任何问题。

这是(IMO)最好的解决方案。

于 2009-03-10T22:48:02.863 回答
1

对于 Perforce,您可以使用 p4 tar 之类的工具:

http://public.perforce.com/wiki/P4tar

它使您可以保存和恢复当前的更改列表,进行修复,然后恢复您的工作。您仍然需要将您的更改集成到 main.h,但这会使任务变得更加容易。

于 2009-01-19T20:10:40.797 回答
1

我同意ChrisF的观点:分支将是最自然的解决方案。

我使用 Perforce 已经有一段时间了,确实它在分支方面不如其他 SCM 强大,但可以做到。

诀窍非常简单:为您正在处理的每个任务创建一个分支(每个任务模式的上帝分支),然后切换到它。如果您需要修复其他问题怎么办?很简单,只需在签入所有内容后切换到不同的分支(使用一些您甚至不需要签入的 scms)修复它,然后稍后再返回到您原来的“电子邮件”分支。

于 2009-04-28T09:05:05.617 回答
1

我认为 Perforce 中“纠结的工作副本”问题的解决方案正在搁置

您可以按如下方式在命令行中使用它:

p4搁置-c 123

我通常在 IDE 插件(Visual Studio 或 Eclipse)或 P4V 中使用它。当您搁置时,您可以选择是否要恢复您的文件,基本上是为您的紧急工作准备一个全新的状态。然后,您可以在完成后取消搁置文件以返回中断的工作。

如果您使用的是命令行,您可以为自己创建一个简单的脚本,该脚本既可以上架,也可以在您选择的更改列表中成功还原更改,从而为您提供一个干净的状态:

p4 shelve -c $1 && p4 revert -c $1 //depot/your/branch/...

只需使用更改列表编号作为参数调用它。相反,当您完成其他工作后,您可以从架子上获取文件并按如下方式移除架子,这基本上会将您带到起点:

p4 取消搁置 -c $1 -f -s $1 && p4 搁置 -c $1 -d

于 2016-07-27T17:54:27.723 回答