0%

Git开发协作实践

这篇写一下我们软工小组是如何利用好Git和Github进行开发协作的。

条件

这个玩法还是需要有一些条件的。

  1. 支持科学上网。Github遭受某大型路由器的各种屏蔽,直连是大概率连不上的。
  2. 不满足条件1的话可以选择Gitlab或者自己拿服务器搭建Gitlab。
  3. 一个对Git支持良好的IDE,例如IDEA,VS Code等,后面用熟了再试着用命令行。

安装

首先下载Git客户端,安装所有设置选择默认即可。安装完成之后要设置用户名和邮箱

1
2
3
# 记得根据自己的姓名和邮箱更改
git config --global user.name "John Doe"
git config --global user.email [email protected]

如果挂了科学上网的代理,还需要对Git进行代理设置,命令行操作如下。其中分号后面的粗体部分是HTTP代理的端口,按照自己软件的设置。

1
2
3
# 记得修改端口号
git config --global http.proxy http://127.0.0.1:10809
git config --global https.proxy http://127.0.0.1:10809

IDEA可以用专业版或者社区版,在Git功能上支持没区别。学生可以免费使用专业版

Github

作为全球最大的代码托管网站,主要业务是托管开源软件,也支持私人仓库(private repository)。Github的多人代码协作有两种实现方式,任选其一即可:

  1. 分享private repository给其他人,适合大作业等级的小团队。
  2. 创建organization,然后创建team和private repository,这个适合人比较多的情况。免费版本缺失分支的权限管理等功能,不过对付大作业是足够的。

创建仓库

有几种创建私有仓库的方法。

Github上创建

根据官网的教程创建仓库

创建的时候有两点需要注意:

  1. 使用Private仓库,大作业开源有被抄袭的风险。
  2. 添加README文件,这样Github会自动创建一个main分支。

Github上创建仓库

创建完成之后,利用git clone命令即可把项目克隆到本地。克隆的链接选择HTTPS,SSH会不走代理,非常滴慢。

仓库克隆地址

打开命令行,输入以下命令。默认克隆位置是用户文件夹,如果需要克隆到其他文件夹用cd命令切换。

git clone https://github.com/xxx

如果是第一次克隆Github的仓库,可能会提示登录Github,需要去Github官网上生成Token。新建一个Token,然后权限拉满,最后复制生成的Token作为密码,用户名就是Github的邮箱。

仓库克隆命令

克隆后有一个.git文件夹,里面存有git更改的记录,务必不要删掉这个文件夹。

本地命令行创建

在命令行中用cd命令切换到合适的路径下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## 为该目录创建仓库
git init --initial-branch=main

## 然后手动创建一个README.md文件。

## 添加文件
git add README.md

## 提交更改
## m选项是提交的message,可以自己改。
git commit -m "first commit"

## 指定远程仓库地址,根据自己的仓库地址修改
## 推送之前请仿照第一种方法的操作创建仓库,但是不要添加README
git remote add origin https://github/xxx

## 推送main分支,这里加入了u选项指定
git push -u origin main

利用IDEA创建

官方有写教程

第一部想在设置,Version Control,Github菜单中加入Github账号。选择用Token登录,可以直接点Generate按钮生成,也可以去官网生成

IDEA添加Github账号

用Token登录

生成Token

然后在上方菜单栏Git, Github, Share project on Github就可以一键创建本地仓库,并把本地仓库推送到远端。

提交和推送

拿VS Code举例。在README文件中新增一行,保存。Git检测到了文件更改,点击源代码管理按钮。

更改文件

点开文件可以查看更改对比,点击+号可以暂存更改,然后点击左上角的对勾即可创建代码提交(commit)。提交需要写一条消息(message),中英文均可,不能空着。

更改文件

提交消息

提交完之后只对本地Git仓库做了更改,我们还需要把更改同步到Github上的远程仓库。点击左下角的同步按钮就可以把更改推到(push)远程仓库。

推送

推送确认。

推送确认

Github上可以看到对README文件做的修改。

上述操作命令行版本如下。

1
2
3
4
5
6
7
8
# 如果没有添加过该文件
git add README.md

# 提交
git commit -m "message"

# 推送
git push

gitignore文件

有一些文件或者文件夹是不适合提交到仓库里的,比如编译文件夹,或者是二进制文件(图片、音频或者视频)。通过在.gitignore文件中加入规则可以排除这些文件或者文件夹。

如果已经提交过,但是想通过gitignore排除,可以运行以下的命令来删除。

1
2
git rm -r --cached .
git add .

多分支

上述的操作都围绕着main分支进行的,一个人玩是OK的,如果是多个人一起写代码的话一个分支是不够的,很容易搞出冲突。

首先感谢这篇知乎,写的非常好,推荐一看。

分支有以下几种:

  1. master或者main分支,也就是项目的主分支,Github默认显示的就是这个分支,打Tag发布版本的时候也是默认这个分支。
  2. develop分支,也就是开发分支,作为开发的主线分支。开发分支不建议直接改,如果你在develop分支删掉一些文件,其他人又对这些文件做了更改,并合并到了Github上的的develop分支,拉取提交的时候就会冲突。
  3. feature分支,也就是功能分支。这个是Git协作中最重要的一环,每个写代码的成员都需要开一个功能分支,从develop分支中迁出。每个功能分支修改完之后,再发拉取请求(Pull request)合并代码到develop分支当中。这样的策略保证了每个人的更改在写代码的阶段不会和别人起冲突,如果有冲突可以在Pull request当中手动解决。

对于大作业等级的项目来说,发布(release)分支和热更新(hotfixes)可以都不要,直接发布master(main)就行。

几种分支

创建develop和feature分支

IDEA

先拿IDEA演示下怎么创建分支。

首先点下右下角分支管理的按钮,会显示项目有多少分支。其中远程分支(Remote Branches)是指在Github上存着的分支;本地分支(Local Branches)是指在自己电脑上存着的分支。本地分支只需要切换(Checkout)自己需要的分支就行,例如develop和自己的功能分支。

我首先创建一个develop分支。点击origin/master (origin/main),然后点击New Branch from Selected。这个的意思是从master分支迁出一个新的分支,对应分支图上的第一个操作。迁出的分支内容上和原分支一模一样。这里还有一个默认的Checkout branch的选项,这个的意思是创建完分支将会切换到该分支。

新建分支

切换分支

现在我们只创建了本地分支,我们还需要把这个分支推(Push)到远程仓库中。点击右上角的Push按钮进行推送(如果找不到这个按钮,点击左上角菜单栏的Git,然后点Push)。

推送分支

我们可以看到这里显示我们即将在远程仓库中新增一个对应的远程分支。点击窗口右下的蓝色Push按钮确认Push。

推送确认

成功之后右下角会有消息提示,点开分支界面,我们可以看到远程分支中已经有我们的开发分支了。

推送完成

基于同样的思路,继续创建从develop分支迁出的功能分支。分支名称建议用自己姓名拼音或者拼音首字母,方便其他组员认领分支。

命令行

把上面的操作改为命令行。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 当前是main分支
# 创建develop分支并切换
git checkout -b develop

# 推送,第一次推送要指定远程的分支名称
git push -u origin develop

# 当前是develop分支
# 创建feature分支并切换,分支名称可以用姓名拼音
git checkout -b my-feature

# 推送
git push -u origin my-feature

分支和提交

在IDEA的左下角有一个Git栏目,点开后会以树形图的形式显示分支和提交。

IDEA提交记录

在Github首页上我们也可以查看branch和commit。

Github项目首页的分支和提交

合并分支

IDEA

在菜单栏中的Git, merge中即可合并分支。选择的分支会与当前分支进行合并。如果出现冲突的话IDEA会弹窗让你手动处理,参考

命令行

上面的操作等同于git merge some-branch。如果出现冲突的话用命令行解决起来比较麻烦,新手用IDEA就好了。

Github Pull request

如果要把feature分支的更改合并到develop分支,其实最好的做法还是去Github上开一个Pull request。Github会显示代码差异,并可以让组员一起做代码审查,确保代码没问题后再合并。

项目中点击Pull requests,选择绿色按钮新建一个Pull requests。

新建pull request

首先第一行有两个选择框,分别为两个分支。通俗一点讲,就是前面一个分支把后面那个分支的更改拉到了自己身上,所以叫pull(拉)request。这个功能在Gitlab中叫Merge request,也就是把后面那个分支的更改merge(合并)到前面分支去。为什么叫法有区别呢,因为Github是个主打开源服务的社区,所以是开源团队把别人提交的更改拉到自己的项目中,而GitLab主要负责闭源项目,所以是合并更改到项目中。我这里选择是把ppl产生的更改合并到了develop中。这里的前后分支千万不要选错了,合并之前要再三确认。选完之后下面会有差了多少个提交,确认好之后就可以点击创建pull request。如果绿色的able to merge没有出现,那就是有冲突发生,还是可以继续创建pull request,后面单独说怎么解决。

选择分支新建pull request

pull request创建之后,如果检测到无冲突,Github就可以一键合并项目。点击merge并确定之后,合并就会自动完成,pull request就关闭了。可以在merge之前让组员一起审核代码,确保代码质量。

可以合并

合并成功之后,还会提示你功能分支可以被安全地删除。但最好不删除,毕竟还要继续写的。

删除分支

最后去IDEA拉取合并的更改。弹窗里面选择merge,不选rebase。

拉取合并

冲突解决

Github在pull request中可能会检测出冲突,但仍然可以继续创建。

Pull request 冲突

创建Pull request后Github会提示去解决冲突。

Pull request 冲突

Github会把每个冲突部分的两个分支的版本都列出来,让我们自行修改。代码改好后,把小于号<<<<<,等于号=====和大于号>>>>>都删掉就可以点击右上方的mark as resolved按钮,告诉Github这个冲突解决完了。

解决冲突

一个文件内冲突全部解决完了

当所有文件都修改好标绿之后,点击右上角的commit merge进行合并。

解决完所有冲突

合并分支

极少数的情况下,可能冲突会复杂到无法利用Github的编辑器进行处理,这个时候得用IDEA或者命令行去处理。

复杂冲突

发布

Github可以一键打包发布我们的源码。首先把develop的更改合并到master或者main分支。

回到Github的仓库界面,点击右边的创建release。

创建release

然后选写上版本号,标题就可以发布了。还可以在下面加入描述。这里默认发布的是master (main)分支。可以把编译好的程序拖到下方添加。如果把下面的pre-lease打上勾就是测试版本,不会在GitHub上直接显示。

设置release

发布完成之后,就可以下载这个项目的源码了,git文件夹会被自动去除。

查看发布

Github Action

安利一下Github的CI/CD工具,Github Action,支持自动化测试、编译和发布项目。免费用户一个月也有2000分钟的执行时间,绰绰有余。

以一个React应用为例子,我们可以利用Github Action完成npm编译,并把编译好的网页发送到云服务器上。

先确保拥有一对SSH的密钥,如果没有的话利用下面的命令进行创建,中间全部回车继续。

1
ssh-keygen -t ed25519 -C "[email protected]"

在Github项目中点击Actions,然后创建。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
name: project

# 在推送到release分支后会被触发,也可以手动触发。
on:
push:
branches: [ release ]
pull_request:
branches: [ release ]
workflow_dispatch:


jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x]

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}

- name: Cache dependencies
uses: actions/cache@v2
with:
path: |
**/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

- name: Install dependencies
run:
npm install

- name: Build
run: |
npm run build

# 打包编译文件为压缩包
- name: Generate artifact
uses: actions/upload-artifact@v3
with:
name: artifact-name
path: ./build

# 加入私钥和known_hosts
- name: Create ssh key
run: |
install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_IP }} >> ~/.ssh/known_hosts

# 通过rsync把编译好的网页同步到服务器上
# 记得修改同步的目的地址
- name: Deploy with rsync
run: |
sudo su
rsync -rav --delete build/ $HOST_USER@$HOST_IP:/location/for/website
env:
HOST_USER: ${{ secrets.SSH_USER}}
HOST_IP: ${{ secrets.SSH_IP}}

创建好之后需要在项目的setting, security, secrets中加入以下密钥。

  1. SSH_USER 服务器的用户名,确保在~/.ssh/authorized_keys文件中添加了SSH公钥
  2. SSH_IP 服务器的IP地址
  3. SSH_PRIVATE_KEY 连接SSH服务器的私钥文件

小结

Git的基本操作还是比较简单的,可以先用IDE用熟,再去学习怎么操作命令行。

Github现在支持无限个私有仓库,无论是一个人写,还是几个人一起写,用起来非常方便。

多分支协作开发需要通过一次大作业或者实习来练习,用熟之后可以避免最后再去合并代码,平时写好一个功能就可以合并分支,然后进行测试。