git-multirepo 1.0.0.beta45 → 1.0.0.beta46
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 +4 -4
- data/.gitattributes +2 -2
- data/.gitbugtraq +3 -3
- data/.gitignore +38 -38
- data/.multirepo +21 -21
- data/.multirepo.lock +26 -26
- data/.multirepo.meta +2 -2
- data/.rspec +2 -2
- data/Gemfile +4 -4
- data/Gemfile.lock +42 -42
- data/LICENSE +22 -22
- data/README.md +154 -144
- data/Rakefile +2 -2
- data/bin/multi +10 -10
- data/docs/bug-repros/91565510-repro.sh +20 -20
- data/docs/git-multirepo-cheatsheet.docx +0 -0
- data/git-multirepo.gemspec +31 -31
- data/lib/commands.rb +14 -14
- data/lib/git-multirepo.rb +2 -2
- data/lib/info.rb +4 -4
- data/lib/multirepo/commands/add-command.rb +50 -50
- data/lib/multirepo/commands/branch-command.rb +81 -81
- data/lib/multirepo/commands/checkout-command.rb +119 -119
- data/lib/multirepo/commands/clone-command.rb +67 -67
- data/lib/multirepo/commands/command.rb +89 -89
- data/lib/multirepo/commands/do-command.rb +102 -100
- data/lib/multirepo/commands/graph-command.rb +42 -42
- data/lib/multirepo/commands/init-command.rb +119 -119
- data/lib/multirepo/commands/inspect-command.rb +38 -39
- data/lib/multirepo/commands/install-command.rb +146 -137
- data/lib/multirepo/commands/merge-command.rb +225 -225
- data/lib/multirepo/commands/open-command.rb +56 -55
- data/lib/multirepo/commands/remove-command.rb +47 -47
- data/lib/multirepo/commands/uninit-command.rb +17 -17
- data/lib/multirepo/commands/update-command.rb +55 -55
- data/lib/multirepo/config.rb +15 -15
- data/lib/multirepo/files/config-entry.rb +38 -38
- data/lib/multirepo/files/config-file.rb +45 -45
- data/lib/multirepo/files/lock-entry.rb +28 -28
- data/lib/multirepo/files/lock-file.rb +55 -55
- data/lib/multirepo/files/meta-file.rb +40 -40
- data/lib/multirepo/files/tracking-file.rb +8 -8
- data/lib/multirepo/files/tracking-files.rb +46 -46
- data/lib/multirepo/git/branch.rb +31 -31
- data/lib/multirepo/git/change.rb +10 -10
- data/lib/multirepo/git/commit.rb +6 -6
- data/lib/multirepo/git/git-runner.rb +46 -46
- data/lib/multirepo/git/git.rb +9 -9
- data/lib/multirepo/git/ref.rb +37 -37
- data/lib/multirepo/git/remote.rb +16 -16
- data/lib/multirepo/git/repo.rb +122 -122
- data/lib/multirepo/hooks/post-commit-hook.rb +22 -22
- data/lib/multirepo/hooks/pre-commit-hook.rb +34 -34
- data/lib/multirepo/logic/dependency.rb +5 -5
- data/lib/multirepo/logic/merge-descriptor.rb +94 -94
- data/lib/multirepo/logic/node.rb +71 -71
- data/lib/multirepo/logic/performer.rb +56 -56
- data/lib/multirepo/logic/revision-selector.rb +34 -34
- data/lib/multirepo/multirepo-exception.rb +5 -5
- data/lib/multirepo/utility/console.rb +51 -51
- data/lib/multirepo/utility/runner.rb +34 -34
- data/lib/multirepo/utility/utils.rb +94 -94
- data/resources/.gitconfig +2 -2
- data/resources/post-commit +5 -5
- data/resources/pre-commit +5 -5
- data/spec/integration/init_spec.rb +18 -18
- data/spec/spec_helper.rb +89 -89
- metadata +2 -2
@@ -1,47 +1,47 @@
|
|
1
|
-
require "multirepo/git/git-runner"
|
2
|
-
require_relative "meta-file"
|
3
|
-
require_relative "lock-file"
|
4
|
-
|
5
|
-
module MultiRepo
|
6
|
-
class TrackingFiles
|
7
|
-
attr_accessor :files
|
8
|
-
|
9
|
-
def initialize(path)
|
10
|
-
@path = path
|
11
|
-
@files = [MetaFile.new(path), LockFile.new(path)]
|
12
|
-
end
|
13
|
-
|
14
|
-
def update
|
15
|
-
updated = false
|
16
|
-
files.each { |f| updated |= f.update }
|
17
|
-
return updated
|
18
|
-
end
|
19
|
-
|
20
|
-
def stage
|
21
|
-
GitRunner.run_in_working_dir(@path, "add --force -- #{files_pathspec}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
22
|
-
end
|
23
|
-
|
24
|
-
def commit(message)
|
25
|
-
stage
|
26
|
-
|
27
|
-
output = GitRunner.run_in_working_dir(@path, "ls-files --modified --others -- #{files_pathspec}", Runner::Verbosity::OUTPUT_NEVER)
|
28
|
-
files_are_untracked_or_modified = output.strip != ""
|
29
|
-
|
30
|
-
output = GitRunner.run_in_working_dir(@path, "diff --name-only --cached -- #{files_pathspec}", Runner::Verbosity::OUTPUT_NEVER)
|
31
|
-
files_are_staged = output.strip != ""
|
32
|
-
|
33
|
-
must_commit = files_are_untracked_or_modified || files_are_staged
|
34
|
-
GitRunner.run_in_working_dir(@path, "commit --no-verify -m \"#{message}\" --only -- #{files_pathspec}", Runner::Verbosity::OUTPUT_ON_ERROR) if must_commit
|
35
|
-
|
36
|
-
return must_commit
|
37
|
-
end
|
38
|
-
|
39
|
-
def delete
|
40
|
-
files.each { |f| FileUtils.rm_f(f.file) }
|
41
|
-
end
|
42
|
-
|
43
|
-
def files_pathspec
|
44
|
-
files.map{ |f| File.basename(f.file) }.join(" ")
|
45
|
-
end
|
46
|
-
end
|
1
|
+
require "multirepo/git/git-runner"
|
2
|
+
require_relative "meta-file"
|
3
|
+
require_relative "lock-file"
|
4
|
+
|
5
|
+
module MultiRepo
|
6
|
+
class TrackingFiles
|
7
|
+
attr_accessor :files
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
@files = [MetaFile.new(path), LockFile.new(path)]
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
updated = false
|
16
|
+
files.each { |f| updated |= f.update }
|
17
|
+
return updated
|
18
|
+
end
|
19
|
+
|
20
|
+
def stage
|
21
|
+
GitRunner.run_in_working_dir(@path, "add --force -- #{files_pathspec}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
22
|
+
end
|
23
|
+
|
24
|
+
def commit(message)
|
25
|
+
stage
|
26
|
+
|
27
|
+
output = GitRunner.run_in_working_dir(@path, "ls-files --modified --others -- #{files_pathspec}", Runner::Verbosity::OUTPUT_NEVER)
|
28
|
+
files_are_untracked_or_modified = output.strip != ""
|
29
|
+
|
30
|
+
output = GitRunner.run_in_working_dir(@path, "diff --name-only --cached -- #{files_pathspec}", Runner::Verbosity::OUTPUT_NEVER)
|
31
|
+
files_are_staged = output.strip != ""
|
32
|
+
|
33
|
+
must_commit = files_are_untracked_or_modified || files_are_staged
|
34
|
+
GitRunner.run_in_working_dir(@path, "commit --no-verify -m \"#{message}\" --only -- #{files_pathspec}", Runner::Verbosity::OUTPUT_ON_ERROR) if must_commit
|
35
|
+
|
36
|
+
return must_commit
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete
|
40
|
+
files.each { |f| FileUtils.rm_f(f.file) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def files_pathspec
|
44
|
+
files.map{ |f| File.basename(f.file) }.join(" ")
|
45
|
+
end
|
46
|
+
end
|
47
47
|
end
|
data/lib/multirepo/git/branch.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
require_relative "ref"
|
2
|
-
require_relative "git-runner"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class Branch < Ref
|
6
|
-
def exists?
|
7
|
-
lines = GitRunner.run_in_working_dir(@repo.path, "branch", Runner::Verbosity::OUTPUT_NEVER).split("\n")
|
8
|
-
branch_names = lines.map { |line| line.tr("* ", "")}
|
9
|
-
branch_names.include?(@name)
|
10
|
-
end
|
11
|
-
|
12
|
-
def upstream_branch
|
13
|
-
output = GitRunner.run_in_working_dir(@repo.path, "config --get branch.#{@name}.merge", Runner::Verbosity::OUTPUT_NEVER)
|
14
|
-
output.sub!("refs/heads/", "")
|
15
|
-
return nil if output == ""
|
16
|
-
Branch.new(@repo, "origin/#{output}")
|
17
|
-
end
|
18
|
-
|
19
|
-
def create
|
20
|
-
GitRunner.run_in_working_dir(@repo.path, "branch #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
21
|
-
end
|
22
|
-
|
23
|
-
def push
|
24
|
-
GitRunner.run_in_working_dir(@repo.path, "push -u origin #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
25
|
-
end
|
26
|
-
|
27
|
-
def checkout
|
28
|
-
GitRunner.run_in_working_dir(@repo.path, "checkout #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
29
|
-
GitRunner.last_command_succeeded
|
30
|
-
end
|
31
|
-
end
|
1
|
+
require_relative "ref"
|
2
|
+
require_relative "git-runner"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class Branch < Ref
|
6
|
+
def exists?
|
7
|
+
lines = GitRunner.run_in_working_dir(@repo.path, "branch", Runner::Verbosity::OUTPUT_NEVER).split("\n")
|
8
|
+
branch_names = lines.map { |line| line.tr("* ", "")}
|
9
|
+
branch_names.include?(@name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def upstream_branch
|
13
|
+
output = GitRunner.run_in_working_dir(@repo.path, "config --get branch.#{@name}.merge", Runner::Verbosity::OUTPUT_NEVER)
|
14
|
+
output.sub!("refs/heads/", "")
|
15
|
+
return nil if output == ""
|
16
|
+
Branch.new(@repo, "origin/#{output}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
GitRunner.run_in_working_dir(@repo.path, "branch #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
21
|
+
end
|
22
|
+
|
23
|
+
def push
|
24
|
+
GitRunner.run_in_working_dir(@repo.path, "push -u origin #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
25
|
+
end
|
26
|
+
|
27
|
+
def checkout
|
28
|
+
GitRunner.run_in_working_dir(@repo.path, "checkout #{@name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
29
|
+
GitRunner.last_command_succeeded
|
30
|
+
end
|
31
|
+
end
|
32
32
|
end
|
data/lib/multirepo/git/change.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
module MultiRepo
|
2
|
-
class Change
|
3
|
-
attr_accessor :status
|
4
|
-
attr_accessor :path
|
5
|
-
|
6
|
-
def initialize(line)
|
7
|
-
@status = line[0...2].strip
|
8
|
-
@path = line[3..-1]
|
9
|
-
end
|
10
|
-
end
|
1
|
+
module MultiRepo
|
2
|
+
class Change
|
3
|
+
attr_accessor :status
|
4
|
+
attr_accessor :path
|
5
|
+
|
6
|
+
def initialize(line)
|
7
|
+
@status = line[0...2].strip
|
8
|
+
@path = line[3..-1]
|
9
|
+
end
|
10
|
+
end
|
11
11
|
end
|
data/lib/multirepo/git/commit.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require_relative "ref"
|
2
|
-
require_relative "git-runner"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class Commit < Ref
|
6
|
-
end
|
1
|
+
require_relative "ref"
|
2
|
+
require_relative "git-runner"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class Commit < Ref
|
6
|
+
end
|
7
7
|
end
|
@@ -1,47 +1,47 @@
|
|
1
|
-
require "multirepo/utility/runner"
|
2
|
-
require "multirepo/config"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class GitRunner
|
6
|
-
class << self
|
7
|
-
attr_accessor :last_command_succeeded
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.run_in_current_dir(git_command, verbosity)
|
11
|
-
full_command = "#{git_executable} #{git_command}"
|
12
|
-
run(full_command, verbosity)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.run_in_working_dir(path, git_command, verbosity)
|
16
|
-
if path == "."
|
17
|
-
# It is always better to skip -C when running git commands in the
|
18
|
-
# current directory (especially in hooks). Doing this prevents
|
19
|
-
# any future issues because we automatically fallback to non-"-C" for ".".
|
20
|
-
# Fixes bug: https://www.pivotaltracker.com/story/show/94505654
|
21
|
-
return run_in_current_dir(git_command, verbosity)
|
22
|
-
else
|
23
|
-
full_command = "#{git_executable} -C \"#{path}\" #{git_command}";
|
24
|
-
end
|
25
|
-
|
26
|
-
# True fix for the -C flag issue in pre-commit hook where the status command would
|
27
|
-
# fail to provide correct results if a pathspec was provided when performing a commit.
|
28
|
-
# http://thread.gmane.org/gmane.comp.version-control.git/263319/focus=263323
|
29
|
-
|
30
|
-
if Config.instance.running_git_hook
|
31
|
-
full_command = "sh -c 'unset $(git rev-parse --local-env-vars); #{full_command};'"
|
32
|
-
end
|
33
|
-
|
34
|
-
run(full_command, verbosity)
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.run(full_command, verbosity)
|
38
|
-
result = Runner.run(full_command, verbosity)
|
39
|
-
@last_command_succeeded = Runner.last_command_succeeded
|
40
|
-
return result
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.git_executable
|
44
|
-
Config.instance.git_executable || "git"
|
45
|
-
end
|
46
|
-
end
|
1
|
+
require "multirepo/utility/runner"
|
2
|
+
require "multirepo/config"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class GitRunner
|
6
|
+
class << self
|
7
|
+
attr_accessor :last_command_succeeded
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.run_in_current_dir(git_command, verbosity)
|
11
|
+
full_command = "#{git_executable} #{git_command}"
|
12
|
+
run(full_command, verbosity)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.run_in_working_dir(path, git_command, verbosity)
|
16
|
+
if path == "."
|
17
|
+
# It is always better to skip -C when running git commands in the
|
18
|
+
# current directory (especially in hooks). Doing this prevents
|
19
|
+
# any future issues because we automatically fallback to non-"-C" for ".".
|
20
|
+
# Fixes bug: https://www.pivotaltracker.com/story/show/94505654
|
21
|
+
return run_in_current_dir(git_command, verbosity)
|
22
|
+
else
|
23
|
+
full_command = "#{git_executable} -C \"#{path}\" #{git_command}";
|
24
|
+
end
|
25
|
+
|
26
|
+
# True fix for the -C flag issue in pre-commit hook where the status command would
|
27
|
+
# fail to provide correct results if a pathspec was provided when performing a commit.
|
28
|
+
# http://thread.gmane.org/gmane.comp.version-control.git/263319/focus=263323
|
29
|
+
|
30
|
+
if Config.instance.running_git_hook
|
31
|
+
full_command = "sh -c 'unset $(git rev-parse --local-env-vars); #{full_command};'"
|
32
|
+
end
|
33
|
+
|
34
|
+
run(full_command, verbosity)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.run(full_command, verbosity)
|
38
|
+
result = Runner.run(full_command, verbosity)
|
39
|
+
@last_command_succeeded = Runner.last_command_succeeded
|
40
|
+
return result
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.git_executable
|
44
|
+
Config.instance.git_executable || "git"
|
45
|
+
end
|
46
|
+
end
|
47
47
|
end
|
data/lib/multirepo/git/git.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require "multirepo/git/git-runner"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Git
|
5
|
-
def self.valid_branch_name?(name)
|
6
|
-
GitRunner.run_in_current_dir("check-ref-format --branch \"#{name}\"", Runner::Verbosity::OUTPUT_NEVER)
|
7
|
-
GitRunner.last_command_succeeded
|
8
|
-
end
|
9
|
-
end
|
1
|
+
require "multirepo/git/git-runner"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Git
|
5
|
+
def self.valid_branch_name?(name)
|
6
|
+
GitRunner.run_in_current_dir("check-ref-format --branch \"#{name}\"", Runner::Verbosity::OUTPUT_NEVER)
|
7
|
+
GitRunner.last_command_succeeded
|
8
|
+
end
|
9
|
+
end
|
10
10
|
end
|
data/lib/multirepo/git/ref.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
require_relative "git-runner"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Ref
|
5
|
-
attr_accessor :name
|
6
|
-
|
7
|
-
def initialize(repo, name)
|
8
|
-
@repo = repo
|
9
|
-
@name = name
|
10
|
-
end
|
11
|
-
|
12
|
-
def exists?
|
13
|
-
output = GitRunner.run_in_working_dir(@repo.path, "rev-parse --verify --quiet #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
14
|
-
return output != ""
|
15
|
-
end
|
16
|
-
|
17
|
-
def commit_id
|
18
|
-
GitRunner.run_in_working_dir(@repo.path, "rev-parse #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
19
|
-
end
|
20
|
-
|
21
|
-
def short_commit_id
|
22
|
-
GitRunner.run_in_working_dir(@repo.path, "rev-parse --short #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
23
|
-
end
|
24
|
-
|
25
|
-
def is_merge?
|
26
|
-
lines = GitRunner.run_in_working_dir(@repo.path, "cat-file -p #{@name}", Runner::Verbosity::OUTPUT_NEVER).split("\n")
|
27
|
-
parents = lines.grep(/^parent /)
|
28
|
-
return parents.count > 1
|
29
|
-
end
|
30
|
-
|
31
|
-
def can_fast_forward_to?(ref)
|
32
|
-
# http://stackoverflow.com/a/2934062/167983
|
33
|
-
rev_parse_output = GitRunner.run_in_working_dir(@repo.path, "rev-parse #{@name}", Runner::Verbosity::OUTPUT_NEVER)
|
34
|
-
merge_base_output = GitRunner.run_in_working_dir(@repo.path, "merge-base \"#{rev_parse_output}\" \"#{ref.name}\"", Runner::Verbosity::OUTPUT_NEVER)
|
35
|
-
return merge_base_output == rev_parse_output
|
36
|
-
end
|
37
|
-
end
|
1
|
+
require_relative "git-runner"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Ref
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(repo, name)
|
8
|
+
@repo = repo
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def exists?
|
13
|
+
output = GitRunner.run_in_working_dir(@repo.path, "rev-parse --verify --quiet #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
14
|
+
return output != ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def commit_id
|
18
|
+
GitRunner.run_in_working_dir(@repo.path, "rev-parse #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
19
|
+
end
|
20
|
+
|
21
|
+
def short_commit_id
|
22
|
+
GitRunner.run_in_working_dir(@repo.path, "rev-parse --short #{@name}", Runner::Verbosity::OUTPUT_NEVER).strip
|
23
|
+
end
|
24
|
+
|
25
|
+
def is_merge?
|
26
|
+
lines = GitRunner.run_in_working_dir(@repo.path, "cat-file -p #{@name}", Runner::Verbosity::OUTPUT_NEVER).split("\n")
|
27
|
+
parents = lines.grep(/^parent /)
|
28
|
+
return parents.count > 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_fast_forward_to?(ref)
|
32
|
+
# http://stackoverflow.com/a/2934062/167983
|
33
|
+
rev_parse_output = GitRunner.run_in_working_dir(@repo.path, "rev-parse #{@name}", Runner::Verbosity::OUTPUT_NEVER)
|
34
|
+
merge_base_output = GitRunner.run_in_working_dir(@repo.path, "merge-base \"#{rev_parse_output}\" \"#{ref.name}\"", Runner::Verbosity::OUTPUT_NEVER)
|
35
|
+
return merge_base_output == rev_parse_output
|
36
|
+
end
|
37
|
+
end
|
38
38
|
end
|
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_in_working_dir(@repo.path, "config --get remote.#{@name}.url", Runner::Verbosity::OUTPUT_NEVER).strip
|
14
|
-
return output == "" ? nil : output
|
15
|
-
end
|
16
|
-
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_in_working_dir(@repo.path, "config --get remote.#{@name}.url", Runner::Verbosity::OUTPUT_NEVER).strip
|
14
|
+
return output == "" ? nil : output
|
15
|
+
end
|
16
|
+
end
|
17
17
|
end
|
data/lib/multirepo/git/repo.rb
CHANGED
@@ -1,123 +1,123 @@
|
|
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_in_working_dir(@path, "rev-parse --is-inside-work-tree", Runner::Verbosity::OUTPUT_NEVER).strip == "true"
|
21
|
-
end
|
22
|
-
|
23
|
-
def head_born?
|
24
|
-
result = GitRunner.run_in_working_dir(@path, "rev-parse HEAD --", Runner::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(/^refs\/heads\//)
|
38
|
-
end
|
39
|
-
|
40
|
-
def remote_branches
|
41
|
-
branches_by_removing_prefix(/^refs\/remotes\//)
|
42
|
-
end
|
43
|
-
|
44
|
-
def changes
|
45
|
-
output = GitRunner.run_in_working_dir(@path, "status --porcelain", Runner::Verbosity::OUTPUT_NEVER)
|
46
|
-
lines = output.split("\n").each{ |f| f.strip }.delete_if{ |f| f == "" }
|
47
|
-
lines.map { |l| Change.new(l) }
|
48
|
-
end
|
49
|
-
|
50
|
-
# Operations
|
51
|
-
|
52
|
-
def fetch
|
53
|
-
GitRunner.run_in_working_dir(@path, "fetch --prune --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
54
|
-
Runner.last_command_succeeded
|
55
|
-
end
|
56
|
-
|
57
|
-
def clone(url, branch = nil)
|
58
|
-
if branch != nil
|
59
|
-
GitRunner.run_in_current_dir("clone #{url} -b #{branch} #{@path} --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
60
|
-
else
|
61
|
-
GitRunner.run_in_current_dir("clone #{url} #{@path} --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
62
|
-
end
|
63
|
-
Runner.last_command_succeeded
|
64
|
-
end
|
65
|
-
|
66
|
-
def checkout(ref_name)
|
67
|
-
GitRunner.run_in_working_dir(@path, "checkout #{ref_name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
68
|
-
Runner.last_command_succeeded
|
69
|
-
end
|
70
|
-
|
71
|
-
# Current
|
72
|
-
|
73
|
-
def head
|
74
|
-
return nil unless exists? && head_born?
|
75
|
-
Ref.new(self, "HEAD")
|
76
|
-
end
|
77
|
-
|
78
|
-
def current_commit
|
79
|
-
return nil unless exists? && head_born?
|
80
|
-
Commit.new(self, head.commit_id)
|
81
|
-
end
|
82
|
-
|
83
|
-
def current_branch
|
84
|
-
return nil unless exists? && head_born?
|
85
|
-
name = GitRunner.run_in_working_dir(@path, "rev-parse --abbrev-ref HEAD", Runner::Verbosity::OUTPUT_NEVER).strip
|
86
|
-
Branch.new(self, name)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Factory methods
|
90
|
-
|
91
|
-
def ref(name)
|
92
|
-
Ref.new(self, name)
|
93
|
-
end
|
94
|
-
|
95
|
-
def branch(name)
|
96
|
-
Branch.new(self, name)
|
97
|
-
end
|
98
|
-
|
99
|
-
def remote(name)
|
100
|
-
Remote.new(self, name)
|
101
|
-
end
|
102
|
-
|
103
|
-
def commit(id)
|
104
|
-
Commit.new(self, id)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Private helper methods
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def branches_by_removing_prefix(prefix_regex)
|
112
|
-
output = GitRunner.run_in_working_dir(@path, "for-each-ref --format='%(refname)'", Runner::Verbosity::OUTPUT_NEVER)
|
113
|
-
all_refs = output.strip.split("\n")
|
114
|
-
|
115
|
-
# Remove surrounding quotes on Windows
|
116
|
-
all_refs = all_refs.map { |l| l.sub(/^\'/, "").sub(/\'$/, "") }
|
117
|
-
|
118
|
-
full_names = all_refs.select { |r| r =~ prefix_regex }
|
119
|
-
names = full_names.map{ |f| f.sub(prefix_regex, "") }.delete_if{ |n| n =~ /HEAD$/}
|
120
|
-
names.map { |b| Branch.new(self, b) }
|
121
|
-
end
|
122
|
-
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_in_working_dir(@path, "rev-parse --is-inside-work-tree", Runner::Verbosity::OUTPUT_NEVER).strip == "true"
|
21
|
+
end
|
22
|
+
|
23
|
+
def head_born?
|
24
|
+
result = GitRunner.run_in_working_dir(@path, "rev-parse HEAD --", Runner::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(/^refs\/heads\//)
|
38
|
+
end
|
39
|
+
|
40
|
+
def remote_branches
|
41
|
+
branches_by_removing_prefix(/^refs\/remotes\//)
|
42
|
+
end
|
43
|
+
|
44
|
+
def changes
|
45
|
+
output = GitRunner.run_in_working_dir(@path, "status --porcelain", Runner::Verbosity::OUTPUT_NEVER)
|
46
|
+
lines = output.split("\n").each{ |f| f.strip }.delete_if{ |f| f == "" }
|
47
|
+
lines.map { |l| Change.new(l) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Operations
|
51
|
+
|
52
|
+
def fetch
|
53
|
+
GitRunner.run_in_working_dir(@path, "fetch --prune --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
54
|
+
Runner.last_command_succeeded
|
55
|
+
end
|
56
|
+
|
57
|
+
def clone(url, branch = nil)
|
58
|
+
if branch != nil
|
59
|
+
GitRunner.run_in_current_dir("clone #{url} -b #{branch} #{@path} --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
60
|
+
else
|
61
|
+
GitRunner.run_in_current_dir("clone #{url} #{@path} --progress", Runner::Verbosity::OUTPUT_ALWAYS)
|
62
|
+
end
|
63
|
+
Runner.last_command_succeeded
|
64
|
+
end
|
65
|
+
|
66
|
+
def checkout(ref_name)
|
67
|
+
GitRunner.run_in_working_dir(@path, "checkout #{ref_name}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
68
|
+
Runner.last_command_succeeded
|
69
|
+
end
|
70
|
+
|
71
|
+
# Current
|
72
|
+
|
73
|
+
def head
|
74
|
+
return nil unless exists? && head_born?
|
75
|
+
Ref.new(self, "HEAD")
|
76
|
+
end
|
77
|
+
|
78
|
+
def current_commit
|
79
|
+
return nil unless exists? && head_born?
|
80
|
+
Commit.new(self, head.commit_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_branch
|
84
|
+
return nil unless exists? && head_born?
|
85
|
+
name = GitRunner.run_in_working_dir(@path, "rev-parse --abbrev-ref HEAD", Runner::Verbosity::OUTPUT_NEVER).strip
|
86
|
+
Branch.new(self, name)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Factory methods
|
90
|
+
|
91
|
+
def ref(name)
|
92
|
+
Ref.new(self, name)
|
93
|
+
end
|
94
|
+
|
95
|
+
def branch(name)
|
96
|
+
Branch.new(self, name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def remote(name)
|
100
|
+
Remote.new(self, name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def commit(id)
|
104
|
+
Commit.new(self, id)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Private helper methods
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def branches_by_removing_prefix(prefix_regex)
|
112
|
+
output = GitRunner.run_in_working_dir(@path, "for-each-ref --format='%(refname)'", Runner::Verbosity::OUTPUT_NEVER)
|
113
|
+
all_refs = output.strip.split("\n")
|
114
|
+
|
115
|
+
# Remove surrounding quotes on Windows
|
116
|
+
all_refs = all_refs.map { |l| l.sub(/^\'/, "").sub(/\'$/, "") }
|
117
|
+
|
118
|
+
full_names = all_refs.select { |r| r =~ prefix_regex }
|
119
|
+
names = full_names.map{ |f| f.sub(prefix_regex, "") }.delete_if{ |n| n =~ /HEAD$/}
|
120
|
+
names.map { |b| Branch.new(self, b) }
|
121
|
+
end
|
122
|
+
end
|
123
123
|
end
|