P4Python:合并实践指南之如何脚本化integrate流程

本文作者向华是资深游戏开发工程师,拥有8年游戏测试开发经验。他是前原神项目P4 Admin,也是一名持续集成开发者。作为Perforce Helix Core的用户,他结合自身项目实践经验,带来关于文件合并的实操干货。

立即联系Perforce授权合作伙伴——龙智,获得更多关于Perforce Helix Core的咨询、试用、服务等信息。

文件合并是一个开发期项目经常遇到,并且是很多人搞不明白的事情。


希望这篇文章能帮你轻松一点。

什么是合

 

在大多数场景下,P4 的合并是都以 changelist 为单位进行合并的,但最小影响的单元还是文件。

 

比如在发布分支 //Game/rel 提交了一个 bug 修复,对应的 changelist 需要合并到主干分支 //Game/main。这是极其常见的合并场景。

合并操作总体分为两步:

Integrate:生成合并

Resolve & Submit:解决冲突并提交

在 Integrate 这一步,P4 将会生成合并,但本步经常会产生冲突(Conflict)。根据长期工作观察,大家经常出现困惑的是 integrate,本篇重点讲这一步的惯用技法。

第一步产生冲突后,需要处理才能完成提交,这一步就是 Resolve & Submit。我们后续文章再讲。

 

怎么合

 

 

作为专门做 CI 的同学,命令行才是常用的方式,因为这是脚本化的基础。


就像过去使用 Linux 系统,希望创建一个目录树,不大可能在 GUI 界面上点击右键创建一个多达5层的文件夹,基本上都是

 

1
mkdir -p /Country/City/Corpration/BU/Team

 

准确、高效是我们的要求。


对于合并这件事,P4 的命令行操作是

1
p4 integrate -f -c default //Game/main/...@1234,1234 //Game/rel/...p4 integrate -f -c default //Game/main/...@1234,1234 //Game/rel/...

  

其中加了 -f 参数,是用来强制合并 changelist 1234 中涉及到的文件的所有历史版本。

 

这一步操作之后,能够精确完成来自 //Game/main 分支上的 changelist 1234 的合并工作,合并的目标是最后的参数所指向的分支 //Game/rel。

 

怎么自助合

 

非技术同学说了,我不会用命令行,记不住那么多参数,能不能简单点。


为了便于落地和分发该工具,我们做了进一步的工作,使用简洁好用的 P4Python 库完成更人性化的封装。将无需用户探究的参数藏起来,留给用户需要填充的部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import argparse
from P4 import P4, P4Exception
import traceback
 
class P4Integrater:
    def __init__(self):
        """
        初始化 integrate
        """
        self.p4 = P4()
        self.p4.connect()
 
        parser = argparse.ArgumentParser()
 
        parser.add_argument('-s','--src', required=True)
        parser.add_argument('-d', '--dest', required=True)
        parser.add_argument('-c', '--change', required=True)
 
        self.args = parser.parse_args()
 
    def run_integrate(self):
        """
        执行 integrate
        """
        try:
            cmd_params = ['integrate', '-f', '-c', 'default', f'{self.args.src}/...@{self.args.change},{self.args.change}', f'{self.args.dest}/...']
            self.p4.run(cmd_params)
 
            print(f'[!DONE!] {self.args.src} ---> {self.args.dest} @{self.args.change}')
        except P4Exception:
            print(f'=============== Exception ===============')
            traceback.print_exc()
 
if __name__ == "__main__":
    _p = P4Integrater()
    _p.run_integrate()

 

更进一步,通过 Pyinstaller 将其编译成可执行 exe 文件,分发给用户。


最终的执行方式变得尤为简洁:

1
p4integrater.exe -s //Game/main -d //Game/rel -c 1234[!DONE!] //Game/main ---> //Game/rel @1234

  

有些更先进的团队,把这种逻辑再次封装成带图形界面的工具,非技术同事用起来就只需填几个参数,非常方便。

 

怎么批量

 

新目标来了,我这里有一批需要合并的 changelist,对以上合并工具进化一下,可达到以下批处理效果。

1
2
3
4
p4integrater.exe -s //Game/main -d //Game/rel -c 45402,45317,45312
[!DONE!] //Game/main ---> //Game/rel @45402
[!DONE!] //Game/main ---> //Game/rel @45317
[!DONE!] //Game/main ---> //Game/rel @45312

  

进化主要发生在 run_integrate 函数中。

1
2
3
4
5
6
7
8
9
10
# 批量执行 integrate,@func: run_integrate
for ch_num in self.args.change.split(","):
    try:
        cmd_params = ['integrate', '-f', '-c', 'default', f'{self.args.src}/...@{ch_num},{ch_num}', f'{self.args.dest}/...']
        self.p4.run(cmd_params)
 
        print(f'[!DONE!] {self.args.src} ---> {self.args.dest} @{ch_num}')
    except P4Exception:
        print(f'=============== Exception ===============')
        traceback.print_exc()

  

在本篇主要介绍了 p4 integrate 脚本化、批量化的常用方案,实际运用过程中会帮你在合并这件事上节省不少时间。

感谢阅读。

 

如需免费试用Perforce Helix Core,请立即联系Perforce授权合作伙伴——龙智

电话:400-775-5506

邮箱:marketing@shdsd.com

posted @   龙智DevSecOps  阅读(244)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示