git-multirepo 1.0.0.beta42 → 1.0.0.beta43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -2
  3. data/.gitbugtraq +3 -3
  4. data/.gitignore +38 -38
  5. data/.multirepo.meta +2 -2
  6. data/.rspec +2 -2
  7. data/Gemfile +4 -4
  8. data/Gemfile.lock +42 -42
  9. data/LICENSE +22 -22
  10. data/README.md +143 -143
  11. data/Rakefile +2 -2
  12. data/bin/multi +10 -10
  13. data/docs/bug-repros/91565510-repro.sh +20 -20
  14. data/git-multirepo.gemspec +31 -31
  15. data/lib/commands.rb +13 -13
  16. data/lib/git-multirepo.rb +2 -2
  17. data/lib/info.rb +4 -4
  18. data/lib/multirepo/commands/add-command.rb +50 -50
  19. data/lib/multirepo/commands/branch-command.rb +81 -81
  20. data/lib/multirepo/commands/checkout-command.rb +119 -119
  21. data/lib/multirepo/commands/clone-command.rb +67 -67
  22. data/lib/multirepo/commands/command.rb +89 -89
  23. data/lib/multirepo/commands/do-command.rb +100 -100
  24. data/lib/multirepo/commands/graph-command.rb +42 -42
  25. data/lib/multirepo/commands/init-command.rb +119 -119
  26. data/lib/multirepo/commands/install-command.rb +106 -106
  27. data/lib/multirepo/commands/merge-command.rb +225 -225
  28. data/lib/multirepo/commands/open-command.rb +55 -55
  29. data/lib/multirepo/commands/remove-command.rb +47 -47
  30. data/lib/multirepo/commands/uninit-command.rb +17 -17
  31. data/lib/multirepo/commands/update-command.rb +55 -55
  32. data/lib/multirepo/config.rb +15 -15
  33. data/lib/multirepo/files/config-entry.rb +38 -38
  34. data/lib/multirepo/files/config-file.rb +45 -45
  35. data/lib/multirepo/files/lock-entry.rb +28 -28
  36. data/lib/multirepo/files/lock-file.rb +55 -55
  37. data/lib/multirepo/files/meta-file.rb +40 -40
  38. data/lib/multirepo/files/tracking-file.rb +8 -8
  39. data/lib/multirepo/files/tracking-files.rb +46 -46
  40. data/lib/multirepo/git/branch.rb +31 -31
  41. data/lib/multirepo/git/change.rb +10 -10
  42. data/lib/multirepo/git/commit.rb +6 -6
  43. data/lib/multirepo/git/git-runner.rb +46 -46
  44. data/lib/multirepo/git/git.rb +9 -9
  45. data/lib/multirepo/git/ref.rb +37 -37
  46. data/lib/multirepo/git/remote.rb +16 -16
  47. data/lib/multirepo/git/repo.rb +122 -122
  48. data/lib/multirepo/hooks/post-commit-hook.rb +22 -22
  49. data/lib/multirepo/hooks/pre-commit-hook.rb +34 -34
  50. data/lib/multirepo/logic/dependency.rb +5 -5
  51. data/lib/multirepo/logic/merge-descriptor.rb +94 -94
  52. data/lib/multirepo/logic/node.rb +71 -71
  53. data/lib/multirepo/logic/performer.rb +56 -56
  54. data/lib/multirepo/logic/revision-selector.rb +34 -34
  55. data/lib/multirepo/multirepo-exception.rb +5 -5
  56. data/lib/multirepo/utility/console.rb +51 -51
  57. data/lib/multirepo/utility/runner.rb +34 -34
  58. data/lib/multirepo/utility/utils.rb +94 -94
  59. data/resources/.gitconfig +2 -2
  60. data/resources/post-commit +5 -5
  61. data/resources/pre-commit +5 -5
  62. data/spec/integration/init_spec.rb +18 -18
  63. data/spec/spec_helper.rb +89 -89
  64. metadata +2 -2
@@ -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
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
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
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
35
  end
@@ -1,6 +1,6 @@
1
- module MultiRepo
2
- class Dependency
3
- attr_accessor :config_entry
4
- attr_accessor :lock_entry
5
- end
1
+ module MultiRepo
2
+ class Dependency
3
+ attr_accessor :config_entry
4
+ attr_accessor :lock_entry
5
+ end
6
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; "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; "--"
46
- when TheirState::EXACT_REF; "Exact ref".yellow
47
- when TheirState::LOCAL_NO_UPSTREAM; "Not remote-tracking".yellow
48
- when TheirState::UPSTREAM_NO_LOCAL; "Branch is upstream".green
49
- when TheirState::LOCAL_UP_TO_DATE; "Local up-to-date with upstream".green
50
- when TheirState::LOCAL_OUTDATED; "Local outdated compared to upstream".yellow
51
- when TheirState::LOCAL_UPSTREAM_DIVERGED; "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.select{ |b| b.name == their_ref.name }.first
61
- local_branch = repo.local_branches.select{ |b| b.name == their_ref.name }.first
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
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; "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; "--"
46
+ when TheirState::EXACT_REF; "Exact ref".yellow
47
+ when TheirState::LOCAL_NO_UPSTREAM; "Not remote-tracking".yellow
48
+ when TheirState::UPSTREAM_NO_LOCAL; "Branch is upstream".green
49
+ when TheirState::LOCAL_UP_TO_DATE; "Local up-to-date with upstream".green
50
+ when TheirState::LOCAL_OUTDATED; "Local outdated compared to upstream".yellow
51
+ when TheirState::LOCAL_UPSTREAM_DIVERGED; "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.select{ |b| b.name == their_ref.name }.first
61
+ local_branch = repo.local_branches.select{ |b| b.name == their_ref.name }.first
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
95
  end
@@ -1,72 +1,72 @@
1
- require "multirepo/files/config-file"
2
-
3
- module MultiRepo
4
- class Node
5
- attr_accessor :path
6
- attr_accessor :depth
7
- attr_accessor :parent
8
-
9
- def initialize(path, parent = nil, depth = 0)
10
- @path = path
11
- @depth = depth
12
- @parent = parent
13
- end
14
-
15
- def name
16
- Pathname.new(File.expand_path(@path)).basename.to_s
17
- end
18
-
19
- def children
20
- return [] unless Utils.is_multirepo_enabled(@path)
21
- config_entries = ConfigFile.new(@path).load_entries
22
- return config_entries.map { |e| Node.new(e.path, self, @depth + 1) }
23
- end
24
-
25
- def ordered_descendants_including_self
26
- return ordered_descendants.push(self)
27
- end
28
-
29
- def ordered_descendants
30
- descendants = find_descendants_recursive(self)
31
-
32
- unique_paths = descendants.map{ |d| d.path }.uniq
33
- unique_nodes = unique_paths.collect do |path|
34
- nodes_for_path = descendants.select { |d| d.path == path }
35
- next nodes_for_path.sort{ |n| n.depth }.first
36
- end
37
-
38
- return unique_nodes.sort_by{ |d| d.depth }.reverse
39
- end
40
-
41
- def find_descendants_recursive(node)
42
- ensure_no_dependency_cycle(node)
43
-
44
- descendants = node.children
45
- descendants.each { |d| descendants.push(*find_descendants_recursive(d)) }
46
- return descendants
47
- end
48
-
49
- def ensure_no_dependency_cycle(node)
50
- parent = node.parent
51
- visited = []
52
- while parent
53
- visited.push(parent)
54
- if parent == node
55
- Console.log_warning("Dependency cycle detected:")
56
- visited.reverse.each_with_index do |n, i|
57
- description = "[first]" if i == visited.count - 1
58
- description = "itself" if visited.count == 1
59
- Console.log_warning("'#{n.path}' depends on #{description}")
60
- end
61
- raise MultiRepoException, "Dependency cycles are not supported by multirepo."
62
- end
63
- parent = parent.parent # Will eventually be nil (root node), which will break out of the loop
64
- end
65
- end
66
-
67
- def ==(object)
68
- object.class == self.class &&
69
- object.path == @path
70
- end
71
- end
1
+ require "multirepo/files/config-file"
2
+
3
+ module MultiRepo
4
+ class Node
5
+ attr_accessor :path
6
+ attr_accessor :depth
7
+ attr_accessor :parent
8
+
9
+ def initialize(path, parent = nil, depth = 0)
10
+ @path = path
11
+ @depth = depth
12
+ @parent = parent
13
+ end
14
+
15
+ def name
16
+ Pathname.new(File.expand_path(@path)).basename.to_s
17
+ end
18
+
19
+ def children
20
+ return [] unless Utils.is_multirepo_enabled(@path)
21
+ config_entries = ConfigFile.new(@path).load_entries
22
+ return config_entries.map { |e| Node.new(e.path, self, @depth + 1) }
23
+ end
24
+
25
+ def ordered_descendants_including_self
26
+ return ordered_descendants.push(self)
27
+ end
28
+
29
+ def ordered_descendants
30
+ descendants = find_descendants_recursive(self)
31
+
32
+ unique_paths = descendants.map{ |d| d.path }.uniq
33
+ unique_nodes = unique_paths.collect do |path|
34
+ nodes_for_path = descendants.select { |d| d.path == path }
35
+ next nodes_for_path.sort{ |n| n.depth }.first
36
+ end
37
+
38
+ return unique_nodes.sort_by{ |d| d.depth }.reverse
39
+ end
40
+
41
+ def find_descendants_recursive(node)
42
+ ensure_no_dependency_cycle(node)
43
+
44
+ descendants = node.children
45
+ descendants.each { |d| descendants.push(*find_descendants_recursive(d)) }
46
+ return descendants
47
+ end
48
+
49
+ def ensure_no_dependency_cycle(node)
50
+ parent = node.parent
51
+ visited = []
52
+ while parent
53
+ visited.push(parent)
54
+ if parent == node
55
+ Console.log_warning("Dependency cycle detected:")
56
+ visited.reverse.each_with_index do |n, i|
57
+ description = "[first]" if i == visited.count - 1
58
+ description = "itself" if visited.count == 1
59
+ Console.log_warning("'#{n.path}' depends on #{description}")
60
+ end
61
+ raise MultiRepoException, "Dependency cycles are not supported by multirepo."
62
+ end
63
+ parent = parent.parent # Will eventually be nil (root node), which will break out of the loop
64
+ end
65
+ end
66
+
67
+ def ==(object)
68
+ object.class == self.class &&
69
+ object.path == @path
70
+ end
71
+ end
72
72
  end