m-git 2.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +85 -0
- data/lib/m-git.rb +66 -0
- data/lib/m-git/argv.rb +170 -0
- data/lib/m-git/argv/opt.rb +38 -0
- data/lib/m-git/argv/opt_list.rb +71 -0
- data/lib/m-git/argv/parser.rb +66 -0
- data/lib/m-git/base_command.rb +271 -0
- data/lib/m-git/command/add.rb +41 -0
- data/lib/m-git/command/branch.rb +90 -0
- data/lib/m-git/command/checkout.rb +106 -0
- data/lib/m-git/command/clean.rb +64 -0
- data/lib/m-git/command/commit.rb +84 -0
- data/lib/m-git/command/config.rb +202 -0
- data/lib/m-git/command/delete.rb +99 -0
- data/lib/m-git/command/fetch.rb +32 -0
- data/lib/m-git/command/forall.rb +81 -0
- data/lib/m-git/command/info.rb +74 -0
- data/lib/m-git/command/init.rb +324 -0
- data/lib/m-git/command/log.rb +73 -0
- data/lib/m-git/command/merge.rb +381 -0
- data/lib/m-git/command/pull.rb +364 -0
- data/lib/m-git/command/push.rb +311 -0
- data/lib/m-git/command/rebase.rb +348 -0
- data/lib/m-git/command/reset.rb +31 -0
- data/lib/m-git/command/self.rb +223 -0
- data/lib/m-git/command/stash.rb +189 -0
- data/lib/m-git/command/status.rb +135 -0
- data/lib/m-git/command/sync.rb +327 -0
- data/lib/m-git/command/tag.rb +67 -0
- data/lib/m-git/command_manager.rb +24 -0
- data/lib/m-git/error.rb +20 -0
- data/lib/m-git/foundation.rb +25 -0
- data/lib/m-git/foundation/constants.rb +107 -0
- data/lib/m-git/foundation/dir.rb +25 -0
- data/lib/m-git/foundation/duration_recorder.rb +92 -0
- data/lib/m-git/foundation/git_message_parser.rb +50 -0
- data/lib/m-git/foundation/lock.rb +32 -0
- data/lib/m-git/foundation/loger.rb +129 -0
- data/lib/m-git/foundation/mgit_config.rb +222 -0
- data/lib/m-git/foundation/operation_progress_manager.rb +139 -0
- data/lib/m-git/foundation/timer.rb +74 -0
- data/lib/m-git/foundation/utils.rb +361 -0
- data/lib/m-git/hooks_manager.rb +96 -0
- data/lib/m-git/manifest.rb +181 -0
- data/lib/m-git/manifest/cache_manager.rb +44 -0
- data/lib/m-git/manifest/internal.rb +182 -0
- data/lib/m-git/manifest/light_repo.rb +108 -0
- data/lib/m-git/manifest/light_repo_generator.rb +87 -0
- data/lib/m-git/manifest/linter.rb +153 -0
- data/lib/m-git/open_api.rb +427 -0
- data/lib/m-git/open_api/script_download_info.rb +37 -0
- data/lib/m-git/output/output.rb +461 -0
- data/lib/m-git/plugin_manager.rb +112 -0
- data/lib/m-git/repo.rb +133 -0
- data/lib/m-git/repo/status.rb +481 -0
- data/lib/m-git/repo/sync_helper.rb +254 -0
- data/lib/m-git/template.rb +9 -0
- data/lib/m-git/template/local_manifest.rb +27 -0
- data/lib/m-git/template/manifest_hook.rb +28 -0
- data/lib/m-git/template/post_download_hook.rb +29 -0
- data/lib/m-git/template/post_hook.rb +31 -0
- data/lib/m-git/template/pre_exec_hook.rb +31 -0
- data/lib/m-git/template/pre_hook.rb +29 -0
- data/lib/m-git/template/pre_push_hook.rb +32 -0
- data/lib/m-git/version.rb +6 -0
- data/lib/m-git/workspace.rb +648 -0
- data/lib/m-git/workspace/path_helper.rb +56 -0
- data/lib/m-git/workspace/workspace_helper.rb +159 -0
- data/m-git +1 -0
- data/mgit +19 -0
- metadata +218 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
|
5
|
+
class Repo
|
6
|
+
class SyncHelper
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# 同步新仓库
|
11
|
+
#
|
12
|
+
# @param repo [MGigClass::Repo] Repo对象
|
13
|
+
#
|
14
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
15
|
+
#
|
16
|
+
# @param link_git [Boolean] 下载新仓库的时候是否托管.git实体并在工作区创建其软链接
|
17
|
+
#
|
18
|
+
# @return [String, Repo] String:执行结果,成功返回nil,错误返回错误信息,Repo:成功返回nil,错误返回新生成的repo对象
|
19
|
+
#
|
20
|
+
def sync_new_repo(light_repo, root, link_git:true)
|
21
|
+
def __sync_local_repo(light_repo, root, link_git:true)
|
22
|
+
output, repo = nil, nil
|
23
|
+
git_entity = File.join(light_repo.git_store_dir(root), '.git')
|
24
|
+
# 先git clone -- local_git_repo,再软链git_entity,再checkout分支
|
25
|
+
clone_url = "git clone -- #{git_entity} #{light_repo.abs_dest(root)}"
|
26
|
+
Utils.execute_shell_cmd(clone_url) { |stdout, stderr, status|
|
27
|
+
if status.success?
|
28
|
+
repo = Repo.generate_strictly(root, light_repo)
|
29
|
+
repo_git = File.join(repo.path, '.git')
|
30
|
+
manage_git = MGitConfig.query_with_key(root, :managegit)
|
31
|
+
if manage_git && link_git
|
32
|
+
FileUtils.rm_rf(repo_git)
|
33
|
+
Utils.link(git_entity, repo_git)
|
34
|
+
end
|
35
|
+
msg = ''
|
36
|
+
# 如果从本地clone的话,remote url是指向本地的,需要更新
|
37
|
+
error_message = sync_remote_url(repo, light_repo)
|
38
|
+
msg += error_message + "\n" if !error_message.nil?
|
39
|
+
# 本地仓库可能太旧,执行pull更新代码和新分支
|
40
|
+
success, error_message = repo.execute_git_cmd('fetch', '')
|
41
|
+
if !success && !error_message.nil? && error_message.length > 0
|
42
|
+
msg += "由于存在本地仓库源,已从本地克隆,但代码更新失败,请自行fetch最新代码。原因:\n" + error_message + "\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
# 同步锁定点
|
46
|
+
error_message = sync_lock_point(repo, light_repo)
|
47
|
+
msg += error_message if !error_message.nil?
|
48
|
+
|
49
|
+
output = msg.length > 0 ? msg : nil
|
50
|
+
else
|
51
|
+
output = "同步仓库\"#{light_repo.name}\"时clone失败,如果远程仓库不存在,请在配置文件中删除该仓库并重试。原因:\n#{stderr}"
|
52
|
+
end
|
53
|
+
}
|
54
|
+
[output, repo]
|
55
|
+
end
|
56
|
+
|
57
|
+
def __sync_remote_repo(light_repo, root, link_git:true)
|
58
|
+
#
|
59
|
+
output, repo = nil, nil
|
60
|
+
clone_url = light_repo.clone_url(root)
|
61
|
+
|
62
|
+
Utils.execute_shell_cmd(clone_url) { |stdout, stderr, status|
|
63
|
+
if status.success?
|
64
|
+
repo = Repo.generate_strictly(root, light_repo)
|
65
|
+
begin
|
66
|
+
# 查询配置看是否需要托管.git实体, 根据mgit config -s managegit false配置。
|
67
|
+
# 若是,那么.git实体会放在.mgit/source-git/文件夹下
|
68
|
+
manage_git = MGitConfig.query_with_key(root, :managegit)
|
69
|
+
Utils.link_git(repo.path, light_repo.git_store_dir(root)) if manage_git && link_git
|
70
|
+
rescue Error => _
|
71
|
+
end
|
72
|
+
msg = ''
|
73
|
+
# 同步锁定点
|
74
|
+
error_message = sync_lock_point(repo, light_repo)
|
75
|
+
msg += error_message if !error_message.nil?
|
76
|
+
|
77
|
+
output = msg.length > 0 ? msg : nil
|
78
|
+
else
|
79
|
+
output = "同步仓库\"#{light_repo.name}\"时clone失败,如果远程仓库不存在,请在配置文件中删除该仓库并重试。原因:\n#{stderr}"
|
80
|
+
end
|
81
|
+
}
|
82
|
+
|
83
|
+
[output, repo]
|
84
|
+
end
|
85
|
+
|
86
|
+
git_entity = File.join(light_repo.git_store_dir(root), '.git')
|
87
|
+
if File.exist?(git_entity)
|
88
|
+
__sync_local_repo(light_repo, root, link_git: link_git)
|
89
|
+
else
|
90
|
+
__sync_remote_repo(light_repo, root, link_git: link_git)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# 同步已有仓库
|
95
|
+
#
|
96
|
+
# @param repo [Repo] Repo对象
|
97
|
+
#
|
98
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
99
|
+
#
|
100
|
+
# @return [string] 执行结果,成功返回nil,错误返回错误信息
|
101
|
+
#
|
102
|
+
def sync_exist_repo(repo, light_repo)
|
103
|
+
msg = ''
|
104
|
+
|
105
|
+
if light_repo.lock
|
106
|
+
# 同步锁定点
|
107
|
+
error_message = sync_lock_point(repo, light_repo)
|
108
|
+
msg += error_message + "\n" if !error_message.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
# 同步remote url
|
112
|
+
error_message = sync_remote_url(repo, light_repo)
|
113
|
+
msg += error_message + "\n" if !error_message.nil?
|
114
|
+
|
115
|
+
return msg.length > 0 ? msg : nil
|
116
|
+
end
|
117
|
+
|
118
|
+
# 同步锁定点
|
119
|
+
#
|
120
|
+
# @param repo [Repo] Repo对象
|
121
|
+
#
|
122
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
123
|
+
#
|
124
|
+
# @return [string] 执行结果,成功返回nil,错误返回错误信息
|
125
|
+
#
|
126
|
+
def sync_lock_point(repo, light_repo)
|
127
|
+
if repo.status_checker.status == Status::GIT_REPO_STATUS[:dirty]
|
128
|
+
return "#{light_repo.name}有本地改动,无法锁定,请自行清空修改后重试!"
|
129
|
+
end
|
130
|
+
|
131
|
+
if !light_repo.commit_id.nil?
|
132
|
+
return sync_commit_id(repo, light_repo)
|
133
|
+
elsif !light_repo.tag.nil?
|
134
|
+
return sync_tag(repo, light_repo)
|
135
|
+
elsif !light_repo.branch.nil?
|
136
|
+
return sync_branch(repo, light_repo)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# 同步tag
|
141
|
+
# @param repo [Repo] Repo对象
|
142
|
+
#
|
143
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
144
|
+
#
|
145
|
+
# @return [string] 执行结果,成功返回nil,错误返回错误信息
|
146
|
+
#
|
147
|
+
def sync_tag(repo, light_repo)
|
148
|
+
if !light_repo.tag.nil?
|
149
|
+
success, output = repo.execute_git_cmd('checkout', light_repo.tag)
|
150
|
+
return output if !success
|
151
|
+
else
|
152
|
+
return "\"#{repo.path}\"的仓库配置未指定tag!"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# 同步commit id
|
157
|
+
# @param repo [Repo] Repo对象
|
158
|
+
#
|
159
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
160
|
+
#
|
161
|
+
# @return [string] 执行结果,成功返回nil,错误返回错误信息
|
162
|
+
#
|
163
|
+
def sync_commit_id(repo, light_repo)
|
164
|
+
if !light_repo.commit_id.nil?
|
165
|
+
success, output = repo.execute_git_cmd('checkout', light_repo.commit_id)
|
166
|
+
return output if !success
|
167
|
+
else
|
168
|
+
return "\"#{repo.path}\"的仓库配置未指定commit id!"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# 同步分支
|
173
|
+
#
|
174
|
+
# @param repo [Repo] Repo对象
|
175
|
+
#
|
176
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
177
|
+
#
|
178
|
+
# @return [string] 执行结果,成功返回nil,错误返回错误信息
|
179
|
+
#
|
180
|
+
def sync_branch(repo, light_repo)
|
181
|
+
|
182
|
+
current_branch = repo.status_checker.current_branch(strict_mode:false)
|
183
|
+
local_branch_exist = repo.status_checker.local_branch_exist?(light_repo.branch)
|
184
|
+
remote_branch_exist = repo.status_checker.remote_branch_exist?(light_repo.branch)
|
185
|
+
is_dirty = repo.status_checker.status == Status::GIT_REPO_STATUS[:dirty]
|
186
|
+
|
187
|
+
# 当前已在目标切换分支则不操作
|
188
|
+
if current_branch == light_repo.branch
|
189
|
+
return nil
|
190
|
+
|
191
|
+
# 本地或远程存在目标分支则切换
|
192
|
+
elsif local_branch_exist || remote_branch_exist || Utils.branch_exist_on_remote?(light_repo.branch, light_repo.url)
|
193
|
+
|
194
|
+
# 本地无目标分支则先拉取
|
195
|
+
if !local_branch_exist && !remote_branch_exist
|
196
|
+
success, error = repo.execute_git_cmd('fetch', '')
|
197
|
+
return error if !success
|
198
|
+
end
|
199
|
+
|
200
|
+
if !is_dirty
|
201
|
+
success, output = repo.execute_git_cmd('checkout', light_repo.branch)
|
202
|
+
return output if !success
|
203
|
+
else
|
204
|
+
return "本地有改动, 无法切换到分支\"#{light_repo.branch}\", 请处理后重试!"
|
205
|
+
end
|
206
|
+
|
207
|
+
else
|
208
|
+
return "仓库分支\"#{light_repo.branch}\"不存在,请检查是否拼写错误!"
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
# 同步remote url
|
214
|
+
#
|
215
|
+
# @param repo [Repo] Repo对象
|
216
|
+
#
|
217
|
+
# @param light_repo [Manifest::LightRepo] LightRepo对象
|
218
|
+
#
|
219
|
+
# @return [Boolean] 执行结果,成功返回nil,错误返回错误信息
|
220
|
+
#
|
221
|
+
def sync_remote_url(repo, light_repo)
|
222
|
+
return nil if light_repo.url.nil?
|
223
|
+
|
224
|
+
success, output = repo.execute_git_cmd('remote', "set-url origin #{light_repo.url}")
|
225
|
+
return success ? nil : output
|
226
|
+
end
|
227
|
+
|
228
|
+
# 生成本地裸库路径
|
229
|
+
#
|
230
|
+
# @param repo_name [String] 仓库名
|
231
|
+
#
|
232
|
+
# @return [String] 本地裸库路径
|
233
|
+
#
|
234
|
+
def local_bare_git_url(path)
|
235
|
+
if File.exist?(path)
|
236
|
+
return path
|
237
|
+
else
|
238
|
+
return nil
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# 删除失效的仓库目录
|
243
|
+
#
|
244
|
+
# @param repo_abs_path [String] 仓库完整路径
|
245
|
+
#
|
246
|
+
def delete_legacy_repo(repo_abs_path)
|
247
|
+
FileUtils.remove_dir(repo_abs_path, true) if File.exist?(repo_abs_path)
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
require 'm-git/template/local_manifest'
|
4
|
+
require 'm-git/template/manifest_hook'
|
5
|
+
require 'm-git/template/post_download_hook'
|
6
|
+
require 'm-git/template/post_hook'
|
7
|
+
require 'm-git/template/pre_exec_hook'
|
8
|
+
require 'm-git/template/pre_hook'
|
9
|
+
require 'm-git/template/pre_push_hook'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
module_function
|
6
|
+
def default_template
|
7
|
+
return "{
|
8
|
+
\"#{Constants::CONFIG_KEY[:repositories]}\": {
|
9
|
+
|
10
|
+
}
|
11
|
+
}
|
12
|
+
"
|
13
|
+
end
|
14
|
+
|
15
|
+
def local_config_template(config_repo_name)
|
16
|
+
return "{
|
17
|
+
\"#{Constants::CONFIG_KEY[:mgit_excluded]}\": true,
|
18
|
+
\"#{Constants::CONFIG_KEY[:repositories]}\": {
|
19
|
+
\"#{config_repo_name}\": {
|
20
|
+
\"#{Constants::REPO_CONFIG_KEY[:mgit_excluded]}\": false
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
MANIFEST_HOOK_TEMPLATE = '
|
6
|
+
#coding=utf-8
|
7
|
+
|
8
|
+
module MGitTemplate
|
9
|
+
|
10
|
+
class ManifestHook
|
11
|
+
|
12
|
+
# hook接口,用于生成manifest.json文件。文件本地地址必须设置为<PROJ_ROOT>/.mgit/source-config/manifest.json
|
13
|
+
#
|
14
|
+
# 若解析失败,可抛出异常:
|
15
|
+
#
|
16
|
+
# raise MGit::Error.new("失败原因...", type: MGit::MGIT_ERROR_TYPE[:config_generate_error])
|
17
|
+
#
|
18
|
+
# 异常抛出后程序终止
|
19
|
+
def self.run()
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
'
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
POST_DOWNLOAD_HOOK_TEMPLATE = '
|
6
|
+
#coding=utf-8
|
7
|
+
|
8
|
+
module MGitTemplate
|
9
|
+
|
10
|
+
class PostDownloadHook
|
11
|
+
|
12
|
+
# hook接口,单个仓库下载完成后调用
|
13
|
+
#
|
14
|
+
# @param name [String] 下载仓库名
|
15
|
+
#
|
16
|
+
# @param path [String] 下载仓库的本地绝对路径
|
17
|
+
#
|
18
|
+
# @return [Boolean] 是否改动仓库HEAD
|
19
|
+
#
|
20
|
+
def self.run(name, path)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
'
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
POST_CUSTOMIZED_HOOK_TEMPLATE = '
|
6
|
+
#coding=utf-8
|
7
|
+
|
8
|
+
module MGitTemplate
|
9
|
+
|
10
|
+
class PostHook
|
11
|
+
|
12
|
+
# hook接口,用于接受本次指令执行后的数据
|
13
|
+
#
|
14
|
+
# @param cmd [String] 本次执行指令
|
15
|
+
#
|
16
|
+
# @param opts [String] 本次执行指令参数
|
17
|
+
#
|
18
|
+
# @param mgit_root [String] mgit根目录
|
19
|
+
#
|
20
|
+
# @param exec_repos [Array<Manifest::LightRepo>] 本次执行指令的LightRepo数组
|
21
|
+
#
|
22
|
+
def self.run(cmd, opts, mgit_root, exec_repos)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
PRE_CUSTOMIZED_EXEC_HOOK_TEMPLATE = '
|
6
|
+
#coding=utf-8
|
7
|
+
|
8
|
+
module MGitTemplate
|
9
|
+
|
10
|
+
class PreExecHook
|
11
|
+
|
12
|
+
# hook接口,用于接受本次指令执行前的数据
|
13
|
+
#
|
14
|
+
# @param cmd [String] 本次执行指令
|
15
|
+
#
|
16
|
+
# @param opts [String] 本次执行指令参数
|
17
|
+
#
|
18
|
+
# @param mgit_root [String] mgit根目录
|
19
|
+
#
|
20
|
+
# @param exec_repos [Array<Manifest::LightRepo>] 本次执行指令的LightRepo数组
|
21
|
+
#
|
22
|
+
def self.run(cmd, opts, mgit_root, exec_repos)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Template
|
5
|
+
PRE_CUSTOMIZED_HOOK_TEMPLATE = '
|
6
|
+
#coding=utf-8
|
7
|
+
|
8
|
+
module MGitTemplate
|
9
|
+
|
10
|
+
class PreHook
|
11
|
+
|
12
|
+
# hook接口,用于接受本次指令执行前的数据
|
13
|
+
#
|
14
|
+
# @param cmd [String] 本次执行指令
|
15
|
+
#
|
16
|
+
# @param opts [String] 本次执行指令参数
|
17
|
+
#
|
18
|
+
# @param mgit_root [String] mgit根目录
|
19
|
+
#
|
20
|
+
def self.run(cmd, opts, mgit_root)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
'
|
28
|
+
end
|
29
|
+
end
|