git提交代码后同步到svn仓库

需求场景

对于程序员来说,版本控制工具有 gitsvn 可以选择,svn 由于其细致的权限管理配置,在很多公司中仍然有应用场景,但在实际项目开发中,git 由于其优越的分布式架构更受程序员的欢迎。
在大多数程序开发过程中,都会推崇 git 优秀的版本控制思想。

这样就有了一个需求场景,在日常开发中想使用 git,但公司的版本控制又要求存储使用 svn

实现步骤

整体思路步骤为:

1. 自已搭建一个 git 服务器,用于存储各个员工的 git 提交

  • 这里建议使用 gitea 来搭建,以下是 docker 的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3"
services:
gitea-server:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- 3000:3000

2. 在 git 的 hook 点 post-receive 中添加 git 同步 svn 的脚本逻辑

post-receive 的挂载点目录中默认有一个 test.sh,可以在里面修改后挂载 python 执行脚本

1
2
3
4
5
6
echo ${data} | while read p_commit c_commit branch; do
result=$(echo ${branch}| grep "main")
if [ "$result" != "" ];then
python /data/git/repositories/wang_guoliang/test-git.git/hooks/post-receive.d/sync-svn.py $c_commit $p_commit
fi
done

其主要步骤是:

  • 将当次提交的内容检出到指定的缓存目录中
  • 将缓存目录中的文件拷贝到 git svn 目录
  • svn 目录中提交记录

svn 客户端目录要向服务端提交记录,可以用 svn,也可以用 git svn,这里我们使用 git svn 来做,利用其可以指定工作目录的的特点来实现

git-svn 默认包含在 Git 的安装包中,不过在 Ubuntu 中,git-svn 是作为一个独立的 Package 需要额外安装的。

1
sudo apt-get install git-svn

以下是完整的脚本代码:

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# post-receive
# 提交后git同步svn提交记录
# 注意 svn 对接目录需要修改所属用户为git

import os
import sys
import subprocess
import json


argv = sys.argv

# 加载配置
with open("/data/git-svn-config.json", 'r', encoding='UTF-8') as f:
git_svn_config = json.load(f)

# git 检出临时目录
shell_git_tmp_dir = git_svn_config['dir']['git_svn_tmp']
# svn 中转目录
shell_git_svn_dir = git_svn_config['dir']['git_svn']
# svn 地址
svn_repository = git_svn_config['svn']['repository']
# svn 默认用户名
shell_svn_username = git_svn_config['svn']['default_uname']
# svn 默认密码
shell_svn_password = git_svn_config['svn']['default_pwd']


# 初始临时目录
if not os.path.exists(shell_git_tmp_dir):
os.makedirs(shell_git_tmp_dir)
# 初始中转目录
if not os.path.exists(shell_git_svn_dir):
os.makedirs(shell_git_svn_dir)
# 初始git svn项目
if not os.path.exists(shell_git_svn_dir + '/.git'):
git_svn_init_result = subprocess.getoutput(
'echo ' +
shell_svn_password +
' | git svn clone ' +
svn_repository +
' ' +
shell_git_svn_dir +
' --username ' +
shell_svn_username)
print('git_svn_init_result: ' + git_svn_init_result)


# 对每条记录进行提交
def add_commit(line):
lineArr = line.split(' - ')
print(lineArr)
subprocess.getoutput('rm -rf ' + shell_git_tmp_dir + '/.')
subprocess.getoutput('GIT_WORK_TREE=' + shell_git_tmp_dir + ' git checkout ' + argv[1] + ' -f ')
subprocess.getoutput('rm -rf ' + shell_git_tmp_dir + '/.git')
subprocess.getoutput('rm -rf ' + shell_git_svn_dir + '/*')
subprocess.getoutput('cp -r ' + shell_git_tmp_dir + '/. ' + shell_git_svn_dir + '/')
subprocess.getoutput('git --work-tree=' + shell_git_svn_dir + ' --git-dir=' + shell_git_svn_dir + '/.git add . ')
result_commit = subprocess.getoutput(
'git --work-tree=' +
shell_git_svn_dir +
' --git-dir=' +
shell_git_svn_dir +
'/.git commit -m "' +
lineArr[2] +
'"')
print('svn-commit: ' + result_commit)
global shell_svn_username
shell_svn_username = lineArr[1]


# 根据git用户名获取svn用户信息
def find_svn_info(git_uname, notFound={}):
user_list = git_svn_config['user']
for i in range(0, len(user_list)):
if user_list[i]['git']['uname'] == git_uname:
return user_list[i]['svn']
return notFound


def main():
global shell_svn_username
global shell_svn_password

# 查询git仓库的日志并提交记录
log_list = subprocess.getoutput('git log main --pretty=format:"%h - %an - %s" ' + argv[1] + ' ^' + argv[2])
list = log_list.splitlines()
for line in list:
add_commit(line)

# 设置svn提交的帐户和密码
svn_user_info = find_svn_info(shell_svn_username)
if 'uname' in svn_user_info:
shell_svn_username = svn_user_info['uname']
shell_svn_password = svn_user_info['pwd']

# 向svn仓库推送
result_push = subprocess.getoutput(
'echo ' +
shell_svn_password +
' | git --work-tree=' +
shell_git_svn_dir +
' --git-dir=' +
shell_git_svn_dir +
'/.git svn dcommit --username ' +
shell_svn_username)
print('svn-push: ' + result_push)


if __name__ == "__main__":
main()

配置文件git-svn-config.json内容:

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
{
"user": [
{
"git": {
"uname": "wgl",
"email": "wang_guoliang@webape.net"
},
"svn": {
"uname": "wgl",
"pwd": "123456"
}
},
{
"git": {
"uname": "user1",
"email": "usr1@webape.net"
},
"svn": {
"uname": "user1",
"pwd": "123456"
}
},
{
"git": {
"uname": "user2",
"email": "usr2@webape.net"
},
"svn": {
"uname": "user2",
"pwd": "123456"
}
}
],
"dir": {
"git_chk": "/tmp/test-git-check",
"git_svn_tmp": "/tmp/test-git-tmp",
"git_svn": "/tmp/test-git"
},
"svn": {
"repository": "svn://10.28.34.219/cloud-platform",
"default_uname": "user1",
"default_pwd": "123456"
}
}