m-git 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|