Git 用户的 Perforce?

有很多“ Git for Perforce 用户”文档,但似乎很少有相反的。

我以前只使用过 Git,最近开始了一项工作,我必须经常使用 Perforce,并且发现自己在很多时候感到非常困惑。我在 Git 中习惯使用的概念似乎根本没有映射到 Perforce。

是否有人有兴趣为习惯 Git 的人收集一些使用 Perforce 的技巧?

53712 次浏览

可能没有很多这样的文档,因为 Perforce 是一个非常传统的修订控制系统(更接近于 CVS、 Subversion 等) ,通常被认为比现代分布式修订控制系统要简单。

试图将命令从一个映射到另一个并不是正确的方法; 集中式与分布式修订控制系统的概念并不相同。相反,我将描述 Perforce 中一个典型的工作流程:

  1. 对要编辑的每个文件运行 p4 edit。您需要告诉 Perforce 您正在编辑哪些文件。如果要添加新文件,请使用 p4 add。如果要删除文件,请使用 p4 delete
  2. 修改代码。
  3. 运行 p4 change创建变更集。在这里,您可以创建更改的说明,也可以选择在更改集中添加或删除文件。如果需要,您可以运行 p4 change CHANGE_NUMBER以便稍后编辑说明。
  4. 如果需要,可以进行其他代码更改。如果需要添加/编辑/删除其他文件,可以使用 p4 {add,edit,delete} -c CHANGE_NUMBER FILE
  5. 运行 p4 sync从服务器获取最新的更改。
  6. 运行 p4 resolve解决任何同步冲突。
  7. 当您准备好提交更改时,运行 p4 submit -c CHANGE_NUMBER

可以使用 p4 revert将更改还原到文件。

注意,只要多个变更集的文件不重叠,就可以同时处理它们。(Perforce 客户端中的文件一次只能在一个变更集中打开。)如果您有小的、独立的更改,这有时会很方便。

如果您发现自己需要编辑已经在另一个变更集中打开的文件,您可以创建一个单独的 Perforce 客户端,或者通过 p4 shelve隐藏现有的变更集,以备以后使用。(与 git stash不同,搁置不会还原本地树中的文件,因此必须单独还原它们。)

这是我过去几周断断续续研究的东西。还在进化,但可能会有帮助。请注意,我是 Perforce 的员工。

针对 Git 用户的 Perforce 介绍

如果说从 Git 到 Perforce 或从 Perforce 到 Git 是不平凡的,那就太轻描淡写了。作为两个表面上做同样事情的工具,他们的方法是非常不同的。这篇简短的文章将帮助 Git 的新 Perforce 用户了解他们所处的新世界。

在我们深入讨论之前有一个简短的绕道; 如果您更喜欢 Git,那么您可以很好地使用带 Perforce 的 Git。我们提供了一个名为 Git Fusion 的工具,用于生成与 Perforce 服务器保持同步的 Git 存储库。Git 和 Perforce 人员可以和谐地使用相同的代码,大部分不受同事对版本控制的选择的影响。Git Fusion 13.3可从 执行网站获得。它确实需要由 Perforce 管理员安装,但是如果您安装它,您会发现它的存储库切片特性对于 Git 用户来说非常方便。

如果无法说服管理员安装 Git Fusion,那么 Git 自带一个名为 Git-P4的 Perforce 绑定,它允许您使用 Git 在 Perforce 工作区中更改和提交文件。更多相关信息请访问: https://git.wiki.kernel.org/index.php/GitP4

还在这儿? 很好,我们来看看 Perforce。

一些术语的差异需要整理

在深入细节之前,我们需要简要介绍 Git 和 Perforce 之间的一些术语差异。

第一个是 退房。在 Git 中,这就是您如何从给定的分支获得代码副本到您的工作区域的方法。在 Perforce 中,我们从命令行或 GUI P4V“获取最新版本”中称之为 同步。Perforce 使用 P4V 中的 退房或命令行中的 p4 edit表示计划从版本控制系统中更改文件。在本文剩余部分中,我将使用单词 Perforce 意义上的 checkout。

第二个是 Git 承诺和 Perforce 服从。您将在 Git 中提交的位置将在 Perforce 中提交。由于所有操作都是针对共享 Perforce 版本控制服务进行的,因此 Perforce 没有对应于 git push的等价物。同样,我们也没有 pull; 上面的 sync 命令负责为我们获取文件。Perforce 中没有纯本地提交的概念,除非您选择使用下面简要介绍的 P4Sandbox 工具。

Perforce 中的关键概念

如果我要将 Perforce 简化为两个关键概念,我将把重点放在 depot 和 workspace 上。Perforce 存储库是 Perforce 服务器中的文件存储库。Perforce 服务器可以有任意数量的仓库,每个仓库可以包含任意数量的文件。您经常会听到 Perforce 用户交换使用 depot 和 server,但它们是不同的。Perforce 站点可以选择拥有多个服务器,但通常所有文件都在一个服务器中。

Perforce 工作区或客户端是系统中的一个对象,它将 Perforce 服务器中的一组文件映射到用户文件系统中的某个位置。每个用户对于他们使用的每台机器都有一个工作区,并且经常用户对于同一台机器有多个工作区。工作区中最重要的部分是工作区映射或视图。

工作区视图指定应该映射到本地机器的仓库中的文件集。这一点很重要,因为很有可能您不想要服务器上可用的所有文件。工作区视图允许您只选择您所关心的集合。需要注意的是,一个工作区可以映射来自多个仓库的内容,但是只能映射来自一个服务器的内容。

为了在这方面比较 Perforce 和 Git,您可以选择您感兴趣的 Git 回购集合。每个回购协议的范围通常很小,只包含相关文件。这样做的好处是不需要进行任何配置; 您可以对所关心的事情进行 git 克隆,然后就可以完成了。如果您只使用一个或两个存储库,那么这尤其好。使用 Perforce 时,您需要花费一些时间来挑选所需的代码片段。

许多 Perforce 工作室使用能够自动生成工作区视图的流,或者使用脚本或模板工作区生成视图。同样,许多人将工作空间留给用户自己生成。能够在一个工作空间中映射多个模块的一个优势是,您可以轻松地在一个签入中修改多个代码模块; 您可以保证,任何具有类似客户端视图并与您的签入同步的人都将拥有处于正确状态的所有代码。但是,这也可能导致代码过度依赖; 强制分离 Git 可能导致更好的模块化。谢天谢地,Perforce 还支持严格的模块化。这完全取决于您选择如何使用这个工具。

为什么是工作区?

我认为来自 Git 的人很容易感觉到整个工作空间概念带来的麻烦远远大于它的价值。与克隆一些 Git 回购相比,这无疑是正确的。工作区的亮点,以及 Perforce 在这么多年后仍然存在的原因是,工作区是一种极好的方式,可以为开发人员减少数百万个文件项目,同时仍然可以方便地从一个权威的源代码中将所有源代码集中起来构建和发布。工作区是 Perforce 能够像它那样扩展的关键原因之一。

工作空间也很好,因为文件的布局在仓库和布局在用户的机器上可以改变,如果需要的话。许多公司组织他们的仓库,以反映他们的公司的组织,使人们很容易找到的业务单位或项目的内容。然而,他们的构建系统并不关心这种层次结构; 工作空间允许他们以任何对他们的工具有意义的方式重新映射他们的仓库层次结构。我还看到一些公司使用这种方法,这些公司使用非常不灵活的构建系统,这些系统要求代码处于非常特定的配置中,而这些配置完全让人感到困惑。工作区允许这些公司拥有一个可供人类导航的源层次结构,同时他们的构建工具获得了他们所需要的结构。

Perforce 中的工作区不仅用于映射用户希望处理的文件集,而且服务器还使用它们来精确跟踪用户已同步的每个文件的哪些修订版本。这允许系统在同步时向用户发送正确的文件集,而不必扫描文件来查看哪些文件需要更新。对于大量的数据,这可能是一个相当大的性能胜利。这在拥有非常严格的审计规则的行业中也非常流行; Perforce 管理员可以轻松地跟踪和记录哪些开发人员同步了哪些文件。

有关 Perforce 工作区的全部功能的更多信息,请阅读 配置 P4

显式结帐与隐式结帐

对于从 Git 转向 Perforce 的用户来说,最大的挑战之一是显式签出的概念。如果您习惯于 Git/SVN/CVS 更改文件的工作流程,然后告诉版本控制系统查找您已经完成的操作,那么这可能是一个非常痛苦的过渡。

好消息是,如果您这样选择,您可以在 Perforce 中使用 Git 样式的工作流。在 Perforce 中,您可以在工作区上设置“ allwrite”选项。这将告诉 Perforce 所有文件都应该写到磁盘上,并设置可写位。然后,您可以更改任何希望更改的文件,而无需显式地告诉 Perforce。要让 Perforce 协调您所做的更改,可以运行“ p4 status”。它将根据需要打开文件以进行添加、编辑和删除。当这样工作时,你会希望使用“ p4更新”而不是“ p4同步”来从服务器获得新的修订; “ p4更新”在同步之前检查修改,所以如果你还没有运行“ p4状态”,不会阻碍你的本地修改。

为什么要显式结账?

我经常收到的一个问题是“为什么要使用显式签出?”乍一看,这似乎是一个疯狂的设计决定,但显式结帐确实有一些强大的好处。

使用显式签出的一个原因是它消除了扫描文件以查看内容更改的需要。虽然通过计算每个文件的散列来查找差异的小型项目相当便宜,但是我们的许多用户在工作区中有数百万个文件,并且/或者拥有100兆字节的大小(如果不是更大的话)的文件。在这些情况下,计算所有散列是非常耗时的。显式签出允许 Perforce 准确地知道它需要处理哪些文件。这种行为是 Perforce 在游戏、电影和硬件等大型文件行业如此流行的原因之一。

另一个好处是显式签出提供了一种异步通信的形式,让开发人员通常知道他们的同事在做什么,或者至少知道他们在做什么。它可以让您知道您可能想避免在某个特定领域工作,以避免不必要的冲突,或者它可以提醒您团队中的一个新开发人员已经进入了可能不需要编辑的代码。我个人的经验是,我倾向于在 Git 中工作,或者在所有项目中使用 Perforce,在这些项目中,我要么是唯一的贡献者,要么是不经常的贡献者,当我与一个团队紧密合作时,我会进行明确的检查。谢天谢地,这是你的选择。

显式签出与 Perforce 挂起变更列表的概念也很相配。挂起的变更列表是可以将打开的文件放入其中以组织工作的存储桶。在 Git 中,您可能会使用不同的分支作为组织工作的存储桶。分支非常好,但是有时候在实际提交给服务器之前能够将工作组织成多个命名的更改是非常好的。通过 Perforce 模型,可以将多个分支或多个项目映射到一个工作区中,挂起的变更列表使得保持单独的更改组织变得很容易。

如果您使用 IDE 进行开发,比如 VisualStudio 或 Eclipse,我强烈建议您为 IDE 安装 Perforce 插件。大多数 IDE 插件会在您开始编辑它们时自动签出文件,从而使您不必亲自进行签出。

Git 特性的 Perforce 替换

  • git stash = = > p4 shelve
  • Git 本地分支 = = > Perforce 搁板或任务分支
  • 图形用户界面中的 git blame = = > p4 annotate执行时间延迟视图

工作中断

有两个选项可以从 Perforce 版本控制服务中断开(这是我们对 Perforce 服务器的想象术语)。

1)使用 P4Sandbox 进行完整的本地版本控制和本地分支

2)编辑你喜欢的文件,并使用“ p4状态”告诉 Perforce 你做了什么

使用上述两个选项,您可以选择在您的工作区中使用“ allwrite”设置,这样您就不必解锁文件。在这种模式下工作时,您需要使用“ p4更新”命令来同步新文件,而不是“ p4同步”。“ p4更新”将在同步文件之前检查文件是否有更改。

迫使快速启动

以下所有示例都将通过命令行执行。

1)配置到 Perforce 的连接

export P4USER=matt
export P4CLIENT=demo-workspace
export P4PORT=perforce:1666

您可以将这些设置粘贴到您的 shell 配置文件中,使用 p4 set在 Windows 和 OS X 上保存它们,或者使用 Perforce 配置文件。

1)创建一个工作区

p4 workspace


# set your root to where your files should live:
Root: /Users/matt/work


# in the resulting editor change your view to map the depot files you care about
//depot/main/... //demo-workspace/main/...
//depot/dev/...  //demo-workspace/dev/...

2)从服务器获取文件

cd /Users/matt/work
p4 sync

3)检查你要处理的文件并修改它

p4 edit main/foo;
echo cake >> main/foo

4)提交到服务器

p4 submit -d "A trivial edit"

5)运行 p4 help simple查看使用 Perforce 所需的基本命令。

Git 和 p4之间最大的区别在于它们使用不同的抽象单元,而现有的答案都没有提到这一点。

  • 在 git 中,抽象是 补丁 (又名 diff,又名 changeset)。Git 中的提交实际上是在提交的文件的前一个状态和当前状态之间运行 diff的输出。
  • 实际上,抽象是 文件 。P4中的提交是该时间点提交中的文件的完整内容。这被组织成一个变更列表,但是修订本身存储在每个文件的基础上,变更列表只是简单地收集文件的不同修订。

其他一切都源于这种差异。在 git 中进行分支和合并是无痛的,因为从 git 抽象的角度来看,每个文件都可以通过按顺序应用一组补丁来完全重构,因此要合并两个分支,你只需要按正确的顺序将源分支上不存在的所有补丁应用到目标分支上(假设两个分支上没有重叠的补丁)。

因为分支是不同的。Perforce 中的分支操作将把文件从一个子文件夹复制到另一个子文件夹,然后用服务器上的元数据标记文件之间的链接。要将一个文件从一个分支合并到另一个分支(perforce 术语为 integration) ,perforce 将查看源分支的‘ head’处的文件的 完整内容和目标分支的头部的文件的 完整内容,如有必要,使用共同的祖先进行合并。它不能像 git can 那样一个接一个地应用补丁,这意味着手动合并发生得更频繁(而且往往更痛苦)。