git-multirepo 1.0.0.beta70 → 1.0.0.beta71
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 +5 -5
- data/.gitattributes +4 -4
- data/.gitbugtraq +3 -3
- data/.gitignore +38 -38
- data/.rspec +2 -2
- data/.rubocop.yml +79 -79
- data/CHANGELOG.md +116 -112
- data/Gemfile +4 -4
- data/Gemfile.lock +47 -47
- data/LICENSE +22 -22
- data/README.md +178 -178
- data/Rakefile +1 -1
- data/bin/multi +11 -11
- data/docs/bug-repros/91565510-repro.sh +20 -20
- data/git-multirepo.gemspec +31 -31
- data/lib/git-multirepo.rb +3 -3
- data/lib/multirepo/commands/add-command.rb +55 -55
- data/lib/multirepo/commands/branch-command.rb +88 -88
- data/lib/multirepo/commands/checkout-command.rb +127 -127
- data/lib/multirepo/commands/clone-command.rb +68 -68
- data/lib/multirepo/commands/command.rb +87 -87
- data/lib/multirepo/commands/commands.rb +14 -14
- data/lib/multirepo/commands/do-command.rb +101 -101
- data/lib/multirepo/commands/init-command.rb +121 -121
- data/lib/multirepo/commands/inspect-command.rb +48 -48
- data/lib/multirepo/commands/install-command.rb +170 -170
- data/lib/multirepo/commands/merge-command.rb +249 -249
- data/lib/multirepo/commands/open-command.rb +55 -55
- data/lib/multirepo/commands/remove-command.rb +48 -48
- data/lib/multirepo/commands/uninit-command.rb +18 -18
- data/lib/multirepo/commands/update-command.rb +112 -112
- data/lib/multirepo/config.rb +19 -19
- data/lib/multirepo/files/config-entry.rb +39 -39
- data/lib/multirepo/files/config-file.rb +52 -52
- data/lib/multirepo/files/lock-entry.rb +29 -29
- data/lib/multirepo/files/lock-file.rb +62 -62
- data/lib/multirepo/files/meta-file.rb +51 -51
- data/lib/multirepo/files/tracking-file.rb +9 -9
- data/lib/multirepo/files/tracking-files.rb +64 -64
- data/lib/multirepo/git/branch.rb +32 -32
- data/lib/multirepo/git/change.rb +11 -11
- data/lib/multirepo/git/commit.rb +7 -7
- data/lib/multirepo/git/git-runner.rb +56 -56
- data/lib/multirepo/git/git.rb +10 -10
- data/lib/multirepo/git/ref.rb +38 -38
- data/lib/multirepo/git/remote.rb +17 -17
- data/lib/multirepo/git/repo.rb +131 -131
- data/lib/multirepo/hooks/post-commit-hook.rb +23 -23
- data/lib/multirepo/hooks/pre-commit-hook.rb +35 -35
- data/lib/multirepo/info.rb +5 -5
- data/lib/multirepo/logic/dependency.rb +6 -6
- data/lib/multirepo/logic/merge-descriptor.rb +95 -95
- data/lib/multirepo/logic/node.rb +75 -75
- data/lib/multirepo/logic/performer.rb +62 -62
- data/lib/multirepo/logic/repo-selection.rb +25 -25
- data/lib/multirepo/logic/revision-selection.rb +15 -15
- data/lib/multirepo/logic/revision-selector.rb +23 -23
- data/lib/multirepo/logic/version-comparer.rb +10 -10
- data/lib/multirepo/multirepo-exception.rb +6 -6
- data/lib/multirepo/output/extra-output.rb +12 -12
- data/lib/multirepo/output/teamcity-extra-output.rb +11 -11
- data/lib/multirepo/utility/console.rb +52 -52
- data/lib/multirepo/utility/popen-runner.rb +27 -27
- data/lib/multirepo/utility/system-runner.rb +14 -14
- data/lib/multirepo/utility/utils.rb +107 -107
- data/lib/multirepo/utility/verbosity.rb +6 -6
- data/resources/.gitconfig +2 -2
- data/resources/post-commit +0 -0
- data/resources/pre-commit +0 -0
- data/spec/integration/init_spec.rb +19 -19
- data/spec/spec_helper.rb +89 -89
- metadata +3 -3
data/lib/multirepo/git/remote.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
require_relative "git-runner"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Remote
|
5
|
-
attr_accessor :name
|
6
|
-
|
7
|
-
def initialize(repo, name)
|
8
|
-
@repo = repo
|
9
|
-
@name = name
|
10
|
-
end
|
11
|
-
|
12
|
-
def url
|
13
|
-
output = GitRunner.run(@repo.path, "config --get remote.#{@name}.url", Verbosity::OUTPUT_NEVER).strip
|
14
|
-
return output == "" ? nil : output
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
1
|
+
require_relative "git-runner"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Remote
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(repo, name)
|
8
|
+
@repo = repo
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def url
|
13
|
+
output = GitRunner.run(@repo.path, "config --get remote.#{@name}.url", Verbosity::OUTPUT_NEVER).strip
|
14
|
+
return output == "" ? nil : output
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/multirepo/git/repo.rb
CHANGED
@@ -1,131 +1,131 @@
|
|
1
|
-
require_relative "branch"
|
2
|
-
require_relative "remote"
|
3
|
-
require_relative "commit"
|
4
|
-
require_relative "change"
|
5
|
-
|
6
|
-
module MultiRepo
|
7
|
-
class Repo
|
8
|
-
attr_accessor :path
|
9
|
-
attr_accessor :basename
|
10
|
-
|
11
|
-
def initialize(path)
|
12
|
-
@path = path
|
13
|
-
@basename = Pathname.new(path).basename.to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
# Inspection
|
17
|
-
|
18
|
-
def exists?
|
19
|
-
return false unless Dir.exist?("#{@path}/.git")
|
20
|
-
return GitRunner.run(@path, "rev-parse --is-inside-work-tree", Verbosity::OUTPUT_NEVER).strip == "true"
|
21
|
-
end
|
22
|
-
|
23
|
-
def head_born?
|
24
|
-
result = GitRunner.run(@path, "rev-parse HEAD --", Verbosity::OUTPUT_NEVER).strip
|
25
|
-
return !result.start_with?("fatal: bad revision")
|
26
|
-
end
|
27
|
-
|
28
|
-
def current_revision
|
29
|
-
(current_branch || current_commit).name
|
30
|
-
end
|
31
|
-
|
32
|
-
def clean?
|
33
|
-
changes.count == 0
|
34
|
-
end
|
35
|
-
|
36
|
-
def local_branches
|
37
|
-
branches_by_removing_prefix(%r{^refs/heads/})
|
38
|
-
end
|
39
|
-
|
40
|
-
def remote_branches
|
41
|
-
branches_by_removing_prefix(%r{^refs/remotes/})
|
42
|
-
end
|
43
|
-
|
44
|
-
def changes
|
45
|
-
output = GitRunner.run(@path, "status --porcelain", Verbosity::OUTPUT_NEVER)
|
46
|
-
lines = output.split("\n").each(&:strip).delete_if{ |f| f == "" }
|
47
|
-
lines.map { |l| Change.new(l) }
|
48
|
-
end
|
49
|
-
|
50
|
-
# Operations
|
51
|
-
|
52
|
-
def fetch
|
53
|
-
GitRunner.run_as_system(@path, "fetch --prune")
|
54
|
-
GitRunner.last_command_succeeded
|
55
|
-
end
|
56
|
-
|
57
|
-
def clone(url, options = nil)
|
58
|
-
options = {} unless options
|
59
|
-
|
60
|
-
branch = options[:branch]
|
61
|
-
|
62
|
-
command = "clone #{url} #{@path}"
|
63
|
-
command << " -q" if options[:quiet] || false
|
64
|
-
command << " -b #{branch}" if branch
|
65
|
-
command << " --recurse-submodules"
|
66
|
-
command << " --shallow-submodules" if options[:shallow] || false
|
67
|
-
command << " --depth 1" if options[:shallow] || false
|
68
|
-
|
69
|
-
GitRunner.run_as_system(".", command)
|
70
|
-
GitRunner.last_command_succeeded
|
71
|
-
end
|
72
|
-
|
73
|
-
def checkout(ref_name)
|
74
|
-
GitRunner.run(@path, "checkout #{ref_name}", Verbosity::OUTPUT_ON_ERROR)
|
75
|
-
GitRunner.last_command_succeeded
|
76
|
-
end
|
77
|
-
|
78
|
-
# Current
|
79
|
-
|
80
|
-
def head
|
81
|
-
return nil unless exists? && head_born?
|
82
|
-
Ref.new(self, "HEAD")
|
83
|
-
end
|
84
|
-
|
85
|
-
def current_commit
|
86
|
-
return nil unless exists? && head_born?
|
87
|
-
Commit.new(self, head.commit_id)
|
88
|
-
end
|
89
|
-
|
90
|
-
def current_branch
|
91
|
-
return nil unless exists? && head_born?
|
92
|
-
name = GitRunner.run(@path, "rev-parse --abbrev-ref HEAD", Verbosity::OUTPUT_NEVER).strip
|
93
|
-
return nil if name == "HEAD" # Code assumes that current_branch will be nil when we're in floating HEAD
|
94
|
-
Branch.new(self, name)
|
95
|
-
end
|
96
|
-
|
97
|
-
# Factory methods
|
98
|
-
|
99
|
-
def ref(name)
|
100
|
-
Ref.new(self, name)
|
101
|
-
end
|
102
|
-
|
103
|
-
def branch(name)
|
104
|
-
Branch.new(self, name)
|
105
|
-
end
|
106
|
-
|
107
|
-
def remote(name)
|
108
|
-
Remote.new(self, name)
|
109
|
-
end
|
110
|
-
|
111
|
-
def commit(id)
|
112
|
-
Commit.new(self, id)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Private helper methods
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def branches_by_removing_prefix(prefix_regex)
|
120
|
-
output = GitRunner.run(@path, "for-each-ref --format='%(refname)'", Verbosity::OUTPUT_NEVER)
|
121
|
-
all_refs = output.strip.split("\n")
|
122
|
-
|
123
|
-
# Remove surrounding quotes on Windows
|
124
|
-
all_refs = all_refs.map { |l| l.sub(/^\'/, "").sub(/\'$/, "") }
|
125
|
-
|
126
|
-
full_names = all_refs.select { |r| r =~ prefix_regex }
|
127
|
-
names = full_names.map{ |f| f.sub(prefix_regex, "") }.delete_if{ |n| n =~ /HEAD$/ }
|
128
|
-
names.map { |b| Branch.new(self, b) }
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
1
|
+
require_relative "branch"
|
2
|
+
require_relative "remote"
|
3
|
+
require_relative "commit"
|
4
|
+
require_relative "change"
|
5
|
+
|
6
|
+
module MultiRepo
|
7
|
+
class Repo
|
8
|
+
attr_accessor :path
|
9
|
+
attr_accessor :basename
|
10
|
+
|
11
|
+
def initialize(path)
|
12
|
+
@path = path
|
13
|
+
@basename = Pathname.new(path).basename.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
# Inspection
|
17
|
+
|
18
|
+
def exists?
|
19
|
+
return false unless Dir.exist?("#{@path}/.git")
|
20
|
+
return GitRunner.run(@path, "rev-parse --is-inside-work-tree", Verbosity::OUTPUT_NEVER).strip == "true"
|
21
|
+
end
|
22
|
+
|
23
|
+
def head_born?
|
24
|
+
result = GitRunner.run(@path, "rev-parse HEAD --", Verbosity::OUTPUT_NEVER).strip
|
25
|
+
return !result.start_with?("fatal: bad revision")
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_revision
|
29
|
+
(current_branch || current_commit).name
|
30
|
+
end
|
31
|
+
|
32
|
+
def clean?
|
33
|
+
changes.count == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def local_branches
|
37
|
+
branches_by_removing_prefix(%r{^refs/heads/})
|
38
|
+
end
|
39
|
+
|
40
|
+
def remote_branches
|
41
|
+
branches_by_removing_prefix(%r{^refs/remotes/})
|
42
|
+
end
|
43
|
+
|
44
|
+
def changes
|
45
|
+
output = GitRunner.run(@path, "status --porcelain", Verbosity::OUTPUT_NEVER)
|
46
|
+
lines = output.split("\n").each(&:strip).delete_if{ |f| f == "" }
|
47
|
+
lines.map { |l| Change.new(l) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Operations
|
51
|
+
|
52
|
+
def fetch
|
53
|
+
GitRunner.run_as_system(@path, "fetch --prune")
|
54
|
+
GitRunner.last_command_succeeded
|
55
|
+
end
|
56
|
+
|
57
|
+
def clone(url, options = nil)
|
58
|
+
options = {} unless options
|
59
|
+
|
60
|
+
branch = options[:branch]
|
61
|
+
|
62
|
+
command = "clone #{url} #{@path}"
|
63
|
+
command << " -q" if options[:quiet] || false
|
64
|
+
command << " -b #{branch}" if branch
|
65
|
+
command << " --recurse-submodules"
|
66
|
+
command << " --shallow-submodules" if options[:shallow] || false
|
67
|
+
command << " --depth 1" if options[:shallow] || false
|
68
|
+
|
69
|
+
GitRunner.run_as_system(".", command)
|
70
|
+
GitRunner.last_command_succeeded
|
71
|
+
end
|
72
|
+
|
73
|
+
def checkout(ref_name)
|
74
|
+
GitRunner.run(@path, "checkout #{ref_name}", Verbosity::OUTPUT_ON_ERROR)
|
75
|
+
GitRunner.last_command_succeeded
|
76
|
+
end
|
77
|
+
|
78
|
+
# Current
|
79
|
+
|
80
|
+
def head
|
81
|
+
return nil unless exists? && head_born?
|
82
|
+
Ref.new(self, "HEAD")
|
83
|
+
end
|
84
|
+
|
85
|
+
def current_commit
|
86
|
+
return nil unless exists? && head_born?
|
87
|
+
Commit.new(self, head.commit_id)
|
88
|
+
end
|
89
|
+
|
90
|
+
def current_branch
|
91
|
+
return nil unless exists? && head_born?
|
92
|
+
name = GitRunner.run(@path, "rev-parse --abbrev-ref HEAD", Verbosity::OUTPUT_NEVER).strip
|
93
|
+
return nil if name == "HEAD" # Code assumes that current_branch will be nil when we're in floating HEAD
|
94
|
+
Branch.new(self, name)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Factory methods
|
98
|
+
|
99
|
+
def ref(name)
|
100
|
+
Ref.new(self, name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def branch(name)
|
104
|
+
Branch.new(self, name)
|
105
|
+
end
|
106
|
+
|
107
|
+
def remote(name)
|
108
|
+
Remote.new(self, name)
|
109
|
+
end
|
110
|
+
|
111
|
+
def commit(id)
|
112
|
+
Commit.new(self, id)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Private helper methods
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def branches_by_removing_prefix(prefix_regex)
|
120
|
+
output = GitRunner.run(@path, "for-each-ref --format='%(refname)'", Verbosity::OUTPUT_NEVER)
|
121
|
+
all_refs = output.strip.split("\n")
|
122
|
+
|
123
|
+
# Remove surrounding quotes on Windows
|
124
|
+
all_refs = all_refs.map { |l| l.sub(/^\'/, "").sub(/\'$/, "") }
|
125
|
+
|
126
|
+
full_names = all_refs.select { |r| r =~ prefix_regex }
|
127
|
+
names = full_names.map{ |f| f.sub(prefix_regex, "") }.delete_if{ |n| n =~ /HEAD$/ }
|
128
|
+
names.map { |b| Branch.new(self, b) }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -1,23 +1,23 @@
|
|
1
|
-
require "multirepo/files/config-file"
|
2
|
-
require "multirepo/files/tracking-files"
|
3
|
-
require "multirepo/utility/utils"
|
4
|
-
require "multirepo/utility/console"
|
5
|
-
|
6
|
-
module MultiRepo
|
7
|
-
class PostCommitHook
|
8
|
-
def self.run
|
9
|
-
Config.instance.running_git_hook = true
|
10
|
-
|
11
|
-
Console.log_step("Performing post-commit operations...")
|
12
|
-
|
13
|
-
# Works around bug #91565510 (https://www.pivotaltracker.com/story/show/91565510)
|
14
|
-
TrackingFiles.new(".").stage
|
15
|
-
Console.log_info("Cleaned-up staging area")
|
16
|
-
|
17
|
-
exit 0
|
18
|
-
rescue StandardError => e
|
19
|
-
Console.log_error("Post-commit hook failed to execute! #{e.message}")
|
20
|
-
exit 1
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
1
|
+
require "multirepo/files/config-file"
|
2
|
+
require "multirepo/files/tracking-files"
|
3
|
+
require "multirepo/utility/utils"
|
4
|
+
require "multirepo/utility/console"
|
5
|
+
|
6
|
+
module MultiRepo
|
7
|
+
class PostCommitHook
|
8
|
+
def self.run
|
9
|
+
Config.instance.running_git_hook = true
|
10
|
+
|
11
|
+
Console.log_step("Performing post-commit operations...")
|
12
|
+
|
13
|
+
# Works around bug #91565510 (https://www.pivotaltracker.com/story/show/91565510)
|
14
|
+
TrackingFiles.new(".").stage
|
15
|
+
Console.log_info("Cleaned-up staging area")
|
16
|
+
|
17
|
+
exit 0
|
18
|
+
rescue StandardError => e
|
19
|
+
Console.log_error("Post-commit hook failed to execute! #{e.message}")
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,35 +1,35 @@
|
|
1
|
-
require "multirepo/files/config-file"
|
2
|
-
require "multirepo/files/tracking-files"
|
3
|
-
require "multirepo/utility/utils"
|
4
|
-
require "multirepo/utility/console"
|
5
|
-
|
6
|
-
module MultiRepo
|
7
|
-
class PreCommitHook
|
8
|
-
def self.run
|
9
|
-
Config.instance.running_git_hook = true
|
10
|
-
|
11
|
-
Console.log_step("Performing pre-commit operations...")
|
12
|
-
|
13
|
-
dependencies_clean = Utils.dependencies_clean?(ConfigFile.new(".").load_entries)
|
14
|
-
|
15
|
-
unless dependencies_clean
|
16
|
-
Console.log_error("You must commit changes to your dependencies before you can commit this repo")
|
17
|
-
exit 1
|
18
|
-
end
|
19
|
-
|
20
|
-
tracking_files = TrackingFiles.new(".")
|
21
|
-
tracking_files.update
|
22
|
-
tracking_files.stage
|
23
|
-
|
24
|
-
Console.log_info("Updated and staged tracking files")
|
25
|
-
|
26
|
-
exit 0
|
27
|
-
rescue MultiRepoException => e
|
28
|
-
Console.log_error("Can't perform commit. #{e.message}")
|
29
|
-
exit 1
|
30
|
-
rescue StandardError => e
|
31
|
-
Console.log_error("Pre-commit hook failed to execute! #{e.message}")
|
32
|
-
exit 1
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
1
|
+
require "multirepo/files/config-file"
|
2
|
+
require "multirepo/files/tracking-files"
|
3
|
+
require "multirepo/utility/utils"
|
4
|
+
require "multirepo/utility/console"
|
5
|
+
|
6
|
+
module MultiRepo
|
7
|
+
class PreCommitHook
|
8
|
+
def self.run
|
9
|
+
Config.instance.running_git_hook = true
|
10
|
+
|
11
|
+
Console.log_step("Performing pre-commit operations...")
|
12
|
+
|
13
|
+
dependencies_clean = Utils.dependencies_clean?(ConfigFile.new(".").load_entries)
|
14
|
+
|
15
|
+
unless dependencies_clean
|
16
|
+
Console.log_error("You must commit changes to your dependencies before you can commit this repo")
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
tracking_files = TrackingFiles.new(".")
|
21
|
+
tracking_files.update
|
22
|
+
tracking_files.stage
|
23
|
+
|
24
|
+
Console.log_info("Updated and staged tracking files")
|
25
|
+
|
26
|
+
exit 0
|
27
|
+
rescue MultiRepoException => e
|
28
|
+
Console.log_error("Can't perform commit. #{e.message}")
|
29
|
+
exit 1
|
30
|
+
rescue StandardError => e
|
31
|
+
Console.log_error("Pre-commit hook failed to execute! #{e.message}")
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/multirepo/info.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
module MultiRepo
|
2
|
-
NAME = "git-multirepo"
|
3
|
-
VERSION = "1.0.0.
|
4
|
-
DESCRIPTION = "Track multiple Git repositories side-by-side."
|
5
|
-
end
|
1
|
+
module MultiRepo
|
2
|
+
NAME = "git-multirepo"
|
3
|
+
VERSION = "1.0.0.beta71"
|
4
|
+
DESCRIPTION = "Track multiple Git repositories side-by-side."
|
5
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
module MultiRepo
|
2
|
-
class Dependency
|
3
|
-
attr_accessor :config_entry
|
4
|
-
attr_accessor :lock_entry
|
5
|
-
end
|
6
|
-
end
|
1
|
+
module MultiRepo
|
2
|
+
class Dependency
|
3
|
+
attr_accessor :config_entry
|
4
|
+
attr_accessor :lock_entry
|
5
|
+
end
|
6
|
+
end
|
@@ -1,95 +1,95 @@
|
|
1
|
-
require "colored"
|
2
|
-
require "multirepo/git/repo"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class TheirState
|
6
|
-
NON_EXISTENT = 0
|
7
|
-
EXACT_REF = 1
|
8
|
-
LOCAL_NO_UPSTREAM = 2
|
9
|
-
UPSTREAM_NO_LOCAL = 3
|
10
|
-
LOCAL_UP_TO_DATE = 4
|
11
|
-
LOCAL_OUTDATED = 5
|
12
|
-
LOCAL_UPSTREAM_DIVERGED = 6
|
13
|
-
end
|
14
|
-
|
15
|
-
class MergeDescriptor
|
16
|
-
attr_accessor :name
|
17
|
-
attr_accessor :repo
|
18
|
-
attr_accessor :our_revision
|
19
|
-
attr_accessor :their_revision
|
20
|
-
attr_accessor :state
|
21
|
-
|
22
|
-
def initialize(name, repo, our_revision, their_revision)
|
23
|
-
@name = name
|
24
|
-
@repo = repo
|
25
|
-
@our_revision = our_revision
|
26
|
-
@their_revision = their_revision
|
27
|
-
|
28
|
-
# Revisions can be anything: "feature1", "origin/feature1", "b51f3c0", ...
|
29
|
-
their_ref = repo.ref(their_revision)
|
30
|
-
|
31
|
-
@short_commit_id = their_ref.short_commit_id
|
32
|
-
|
33
|
-
@state = determine_merge_state(repo, their_ref)
|
34
|
-
end
|
35
|
-
|
36
|
-
def merge_description
|
37
|
-
case @state
|
38
|
-
when TheirState::NON_EXISTENT then "No revision named #{@their_revision}".red
|
39
|
-
else; "Merge '#{@state == TheirState::EXACT_REF ? @short_commit_id : @their_revision}' into '#{@our_revision}'"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def upstream_description
|
44
|
-
case @state
|
45
|
-
when TheirState::NON_EXISTENT then "--"
|
46
|
-
when TheirState::EXACT_REF then "Exact ref".yellow
|
47
|
-
when TheirState::LOCAL_NO_UPSTREAM then "Not remote-tracking".yellow
|
48
|
-
when TheirState::UPSTREAM_NO_LOCAL then "Branch is upstream".green
|
49
|
-
when TheirState::LOCAL_UP_TO_DATE then "Local up-to-date with upstream".green
|
50
|
-
when TheirState::LOCAL_OUTDATED then "Local outdated compared to upstream".yellow
|
51
|
-
when TheirState::LOCAL_UPSTREAM_DIVERGED then "Local and upstream have diverged!".red
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def determine_merge_state(repo, their_ref)
|
58
|
-
return TheirState::NON_EXISTENT unless their_ref.exists?
|
59
|
-
|
60
|
-
remote_branch = repo.remote_branches.find { |b| b.name == their_ref.name }
|
61
|
-
local_branch = repo.local_branches.find { |b| b.name == their_ref.name }
|
62
|
-
|
63
|
-
# If no local branch nor remote branch exist for their_ref, this is an exact ref
|
64
|
-
return TheirState::EXACT_REF unless remote_branch || local_branch
|
65
|
-
|
66
|
-
# If remote exists but local does not, return UPSTREAM_NO_LOCAL
|
67
|
-
return TheirState::UPSTREAM_NO_LOCAL if remote_branch && !local_branch
|
68
|
-
|
69
|
-
# If there is no upstream, no need to check for differences between local and remote
|
70
|
-
return TheirState::LOCAL_NO_UPSTREAM unless local_branch.upstream_branch
|
71
|
-
|
72
|
-
# Else check local vs upstream state
|
73
|
-
return determine_local_upstream_merge_state(repo, their_ref)
|
74
|
-
end
|
75
|
-
|
76
|
-
def determine_local_upstream_merge_state(repo, their_ref)
|
77
|
-
# We can assume we're working with a branch at this point
|
78
|
-
their_branch = repo.branch(their_ref.name)
|
79
|
-
|
80
|
-
their_upstream_branch = their_branch.upstream_branch
|
81
|
-
local_as_upstream = their_branch.commit_id == their_upstream_branch.commit_id
|
82
|
-
can_fast_forward_local_to_upstream = their_branch.can_fast_forward_to?(their_upstream_branch)
|
83
|
-
|
84
|
-
state = if local_as_upstream
|
85
|
-
TheirState::LOCAL_UP_TO_DATE
|
86
|
-
elsif !local_as_upstream && can_fast_forward_local_to_upstream
|
87
|
-
TheirState::LOCAL_OUTDATED
|
88
|
-
else
|
89
|
-
TheirState::LOCAL_UPSTREAM_DIVERGED
|
90
|
-
end
|
91
|
-
|
92
|
-
return state
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
1
|
+
require "colored"
|
2
|
+
require "multirepo/git/repo"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class TheirState
|
6
|
+
NON_EXISTENT = 0
|
7
|
+
EXACT_REF = 1
|
8
|
+
LOCAL_NO_UPSTREAM = 2
|
9
|
+
UPSTREAM_NO_LOCAL = 3
|
10
|
+
LOCAL_UP_TO_DATE = 4
|
11
|
+
LOCAL_OUTDATED = 5
|
12
|
+
LOCAL_UPSTREAM_DIVERGED = 6
|
13
|
+
end
|
14
|
+
|
15
|
+
class MergeDescriptor
|
16
|
+
attr_accessor :name
|
17
|
+
attr_accessor :repo
|
18
|
+
attr_accessor :our_revision
|
19
|
+
attr_accessor :their_revision
|
20
|
+
attr_accessor :state
|
21
|
+
|
22
|
+
def initialize(name, repo, our_revision, their_revision)
|
23
|
+
@name = name
|
24
|
+
@repo = repo
|
25
|
+
@our_revision = our_revision
|
26
|
+
@their_revision = their_revision
|
27
|
+
|
28
|
+
# Revisions can be anything: "feature1", "origin/feature1", "b51f3c0", ...
|
29
|
+
their_ref = repo.ref(their_revision)
|
30
|
+
|
31
|
+
@short_commit_id = their_ref.short_commit_id
|
32
|
+
|
33
|
+
@state = determine_merge_state(repo, their_ref)
|
34
|
+
end
|
35
|
+
|
36
|
+
def merge_description
|
37
|
+
case @state
|
38
|
+
when TheirState::NON_EXISTENT then "No revision named #{@their_revision}".red
|
39
|
+
else; "Merge '#{@state == TheirState::EXACT_REF ? @short_commit_id : @their_revision}' into '#{@our_revision}'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def upstream_description
|
44
|
+
case @state
|
45
|
+
when TheirState::NON_EXISTENT then "--"
|
46
|
+
when TheirState::EXACT_REF then "Exact ref".yellow
|
47
|
+
when TheirState::LOCAL_NO_UPSTREAM then "Not remote-tracking".yellow
|
48
|
+
when TheirState::UPSTREAM_NO_LOCAL then "Branch is upstream".green
|
49
|
+
when TheirState::LOCAL_UP_TO_DATE then "Local up-to-date with upstream".green
|
50
|
+
when TheirState::LOCAL_OUTDATED then "Local outdated compared to upstream".yellow
|
51
|
+
when TheirState::LOCAL_UPSTREAM_DIVERGED then "Local and upstream have diverged!".red
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def determine_merge_state(repo, their_ref)
|
58
|
+
return TheirState::NON_EXISTENT unless their_ref.exists?
|
59
|
+
|
60
|
+
remote_branch = repo.remote_branches.find { |b| b.name == their_ref.name }
|
61
|
+
local_branch = repo.local_branches.find { |b| b.name == their_ref.name }
|
62
|
+
|
63
|
+
# If no local branch nor remote branch exist for their_ref, this is an exact ref
|
64
|
+
return TheirState::EXACT_REF unless remote_branch || local_branch
|
65
|
+
|
66
|
+
# If remote exists but local does not, return UPSTREAM_NO_LOCAL
|
67
|
+
return TheirState::UPSTREAM_NO_LOCAL if remote_branch && !local_branch
|
68
|
+
|
69
|
+
# If there is no upstream, no need to check for differences between local and remote
|
70
|
+
return TheirState::LOCAL_NO_UPSTREAM unless local_branch.upstream_branch
|
71
|
+
|
72
|
+
# Else check local vs upstream state
|
73
|
+
return determine_local_upstream_merge_state(repo, their_ref)
|
74
|
+
end
|
75
|
+
|
76
|
+
def determine_local_upstream_merge_state(repo, their_ref)
|
77
|
+
# We can assume we're working with a branch at this point
|
78
|
+
their_branch = repo.branch(their_ref.name)
|
79
|
+
|
80
|
+
their_upstream_branch = their_branch.upstream_branch
|
81
|
+
local_as_upstream = their_branch.commit_id == their_upstream_branch.commit_id
|
82
|
+
can_fast_forward_local_to_upstream = their_branch.can_fast_forward_to?(their_upstream_branch)
|
83
|
+
|
84
|
+
state = if local_as_upstream
|
85
|
+
TheirState::LOCAL_UP_TO_DATE
|
86
|
+
elsif !local_as_upstream && can_fast_forward_local_to_upstream
|
87
|
+
TheirState::LOCAL_OUTDATED
|
88
|
+
else
|
89
|
+
TheirState::LOCAL_UPSTREAM_DIVERGED
|
90
|
+
end
|
91
|
+
|
92
|
+
return state
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|