团队 Git 使用记录

Posted by David on 2014-03-10 in Web Development

Migration from Perforce to Git

一直以来团队都是使用 Perforce(以下简称 P4) 来进行集中式代码的管理,但仅仅局限于 checkin 和 checkout,也就是说只是把 P4 作为代码备份仓库在使用,并没有完全真正发挥其应有的功效。

随着业务需求的不断扩大,原有的集中式代码管理方式已经无法适应实际的需要,必须启用带分支的开发方式。在对 P4 的分支管理以及对 Git 的分支管理进行了了解,以及对两者的优缺点进行了对比,最终决定迁移到 Git 上来。

迁移工作不是很复杂,Git 本身就自带了从 P4 到 Git 的迁移工具,通过以下命令就可以很方便的将原 P4 仓库中相应项目的 changelist 都导出到 Git 本地仓库中。

git p4 clone //dev/team/project@all project

在迁移过程中,曾出现某个项目的代码迁移出错:

git p4 clone //dev/team/project1@all project1

Importing from //dev/team/project1@all into project1
Initialized empty Git repository in /Users/voidman/project1/.git/
Traceback (most recent call last):
  File "/usr/local/Cellar/git/1.8.4.1/libexec/git-core/git-p4", line 3398, in 
    main()
  File "/usr/local/Cellar/git/1.8.4.1/libexec/git-core/git-p4", line 3392, in main
    if not cmd.run(args):
  File "/usr/local/Cellar/git/1.8.4.1/libexec/git-core/git-p4", line 3266, in run
    if not P4Sync.run(self, depotPaths):
  File "/usr/local/Cellar/git/1.8.4.1/libexec/git-core/git-p4", line 3097, in run
    changes = p4ChangesForPaths(self.depotPaths, self.changeRange)
  File "/usr/local/Cellar/git/1.8.4.1/libexec/git-core/git-p4", line 762, in p4ChangesForPaths
    changeNum = int(line.split(" ")[1])
IndexError: list index out of range

经过排查发现是该项目的部分 changelist 注释包含了乱码导致迁移脚本的 p4ChangesForPaths 函数出错,其实也是该函数中的部分代码兼容性没做好,简单加了句判断就可以解决该问题:

# 将原代码
for line in output:
    changeNum = int(line.split(" ")[1])
    changes[changeNum] = True

# 修改成
for line in output:
    if " " in line:
        changeNum = int(line.split(" ")[1])
        changes[changeNum] = True

Workflow

迁移到 Git,并不仅仅只是将代码仓库迁移,而是,我们希望借此机会将团队的项目工作流程真正的建立起来,从开发到代码审核到测试到发布,每个环节都能较好地进行进度管理,使工作富有节奏感,达到一个良好的循环状态。所以,我们需要的不仅仅是搭建一个 Git 服务端,而是一个 Git 管理平台。

我们选择了 GitLab 作为我们的 Git 版本管理平台。GitLab 克隆了大部分 GitHub 功能,其中 issue, wiki, merge_request 三个功能是我们比较看重的。issue 可以用作项目任务管理,wiki 用作项目文档编写,merge_request 可以用于代码审核,非常适合我们这样的小团队。代码、任务、文档、代码审核这些在技术开发中比较重要的部分可以通过一个平台就能进行管理,很大程序上会减轻管理的繁琐。

当然,这里最主要的还是讲讲我们采用的 Git workflow. 众所周知,现在比较流行的两种 workflow: A successful Git branching modelGitHub Flow 相比较而言,GitHub Flow 更加简洁,不过个人觉得这对自动化测试、,代码评审质量、自动化发布的要求会比较高,目前不太适合我们团队。在前者的基础上,我们做了一些改进,以更适合我们团队的实际情况。

如同前者,我们将分支分为以下几种类型:

  • master – 主分支,代码处于随时可发布状态
  • develop – 最新开发分支
  • feature branches – 功能开发分支,基于 develop,完成开发、测试后 merge 回 develop
  • release branches – 准备发布分支,基于 develop,完成测试 bug 修正后 merge 回 develop 和master,并在 master 分支打上版本 tag
  • hotfix branches – 一般对应运行在线上版本需要修复 bug 的情况,基于 master 分支,完成 bug 修正测试后,merge 回 master 和 develop
  • 每个项目初始化时都包必须含 master 和 develop 两个分支,master 和 develop 分支受保护,只允许项目负责人管理和合并从其它分支过来的代码。参与项目开发的成员都可以开 branch。为了分支管理和任务跟踪方便,我们要求每一个 branch 都必须对应一个 issue,以 issue 的 tag 为分支的前缀,以 issue id 命名。如:

  • feature_{issue_id}
  • enhancement_{issue_id}
  • bug_{issue_id}
  • hotfix_{issue_id}

注: 对于发布分支,则是以 release_{version} 这样的方式命名。

项目参与人员按照任务需要基于最新的 develop 新建分支,所以要求团队成员每天及时同步 develop 分支。功能开发分支开发完成后要及时推送到版本服务器上的同名分支,这样可以很方便的看到同时有多少个任务是在进行当中的。

代码的合并通过 merge_request 进行,一是可以做到代码审核,二是可以做到合并任务有迹可循。代码合并之前都必须被测试过,我们希望合并到 develop 分支的代码是高质量的。develop 分支的代码每天会被自动同步到测试服务器,以供相关人员测试。

踩到的坑

Line Endings / 换行符

我们期望所有代码中的换行符都是统一采用 LF,于是要求团队成员采用以下设置:

# 使用 windows 的同学
git config --global core.autocrlf true
git config --global core.safecrlf true
    
# 使用 mac 或 linux 的同学
git config --global core.autocrlf input
git config --global core.safecrlf true

autocrlf 的设定没有问题,但没想到 safecrlf 的设定带来了麻烦。本意是希望在各平台开发的时候,若代码中的换行符与系统默认不一致,则拒绝提交。但问题是我们经常会引入第三方库,很有可能第三方库的代码中的换行符与系统不一致,于是我们就把 safecrlf 的设定改为了 warn。

由于 P4 中,默认 diff 是不区分换行符的,所以历史代码中存在不少 CRLF 和 LF 混排的情况。虽然迁移之前做了些了解,对 Git 参数做了相应的设定,但在将代码 push 到服务器之前忘记将历史代码重新 renormalize,导致代码签出之后立即出现大量文件被修改的情况,于是不得不挨个将各个项目的仓库中的代码重新 renormalize,然后重新提交。

find -E . -type f -regex ".*\.(php|css|js|xml|html|htm|txt|md|log)" | xargs dos2unix
#注: Mac OS X 自带的 find 命令 须带 -E 参数
Tags: , .

Comments

No Comments

Trackbacks / Pingbacks

  1. » 2589 – Destiny Guide

Leave a Reply

You can use these XHTML tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>