git-multirepo 1.0.0.beta19 → 1.0.0.beta20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -8
- data/bin/multi +5 -0
- data/lib/commands.rb +0 -1
- data/lib/info.rb +1 -1
- data/lib/multirepo/commands/checkout-command.rb +46 -34
- data/lib/multirepo/commands/clone-command.rb +21 -8
- data/lib/multirepo/commands/install-command.rb +17 -15
- data/lib/multirepo/commands/update-command.rb +0 -5
- data/lib/multirepo/utility/utils.rb +16 -11
- metadata +2 -3
- data/lib/multirepo/commands/edit-command.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 292c05d1335e888a82eeaea12ca7170378669a90
|
4
|
+
data.tar.gz: d8c27f7671954a3aeab46ddb9ad55461dfbac529
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 088543b1a14197625ed68c3aed17bbd8a6b959f638cad894da37f94bca89896249c8152914b9a265727aaf3daee0761a986d213826591ff41ea91ac35e74af59
|
7
|
+
data.tar.gz: d98eb47bc0c08028b255f4f229981d2d2608c2ddfc96710706249e4198a7470e17d4c3415f8b906ed987e500630878ccccadab5070e28c34b642f2d9413dc12d
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# git-multirepo
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/git-multirepo.svg)](http://badge.fury.io/rb/git-multirepo)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/fortinmike/git-multirepo/badges/gpa.svg)](https://codeclimate.com/github/fortinmike/git-multirepo)
|
5
|
+
[![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/fortinmike/git-multirepo/blob/master/LICENSE)
|
4
6
|
|
5
7
|
Track multiple Git repositories side-by-side.
|
6
8
|
|
@@ -64,9 +66,9 @@ Say you want to track an existing project with git-multirepo:
|
|
64
66
|
2. `cd` into the *AwesomeApp* directory (aka the "main repo").
|
65
67
|
3. Run `multi init`.
|
66
68
|
4. You will get prompted to add *Dependency1* and *Dependency2* to multirepo; do so.
|
67
|
-
5. git-multirepo reads all required information from dependency repos and initializes itself, storing its metadata
|
69
|
+
5. git-multirepo reads all required information from dependency repos and initializes itself, storing its metadata in the main repo, under version control.
|
68
70
|
|
69
|
-
From now on, each time you commit the main repo git-multirepo tracks — using
|
71
|
+
From now on, each time you commit the main repo git-multirepo tracks — using local git hooks — which revision of each dependency is required for that main repo revision, and where to get them. The hooks also ensure that you won't commit the main repo before its dependencies so that you always get a valid state stored under version control.
|
70
72
|
|
71
73
|
If you want to add another dependency later on, you can run `multi add ../NewDependency` and you can do the opposite with `multi remove ../SomeOtherDependency`.
|
72
74
|
|
@@ -78,13 +80,14 @@ If you want to stop using git-multirepo, run `multi uninit`. This will remove al
|
|
78
80
|
|
79
81
|
## Advantages
|
80
82
|
|
81
|
-
- Makes setting up
|
82
|
-
-
|
83
|
+
- Makes setting up a project on a new machine a breeze.
|
84
|
+
- Really effective when working on multiple projects that share a common set of constantly evolving dependencies.
|
83
85
|
- Each dependency's repository is totally independent from the main repository, which simplifies a lot of things (merges, contributing upstream, etc.) and works well with git GUIs.
|
84
86
|
- While the repositories are independent, git-multirepo makes sure to track everything that's required to bring back a previous version of your project in a valid state.
|
87
|
+
- It supports sub-dependencies (e.g. dependencies that have dependencies of their own) so that you can bring back any subset of your project in a valid state at will.
|
85
88
|
- Much more approachable to novice developers than submodules or subtrees.
|
86
89
|
- Once setup, there is little need for git-multirepo commands, so you are free to use whatever tools you like to work with your git repos.
|
87
|
-
- Low possibility of human error (such as forgetting to contribute
|
90
|
+
- Low possibility of human error (such as forgetting to contribute changes to dependencies back to the appropriate remotes, forgetting to commit dependencies in the proper order, etc.)
|
88
91
|
- You're not stuck with git-multirepo. It stores its metadata as [YAML](http://www.yaml.org) in the main repo. You can clone and checkout appropriate revisions of your dependencies by hand without git-multirepo if you need to. The information is there, in human-readable form.
|
89
92
|
|
90
93
|
| How It Handles... | git-multirepo | git submodules | git subtrees |
|
@@ -100,8 +103,8 @@ If you want to stop using git-multirepo, run `multi uninit`. This will remove al
|
|
100
103
|
|
101
104
|
## Limitations
|
102
105
|
|
103
|
-
- git-multirepo should be considered beta at the moment.
|
104
|
-
- The project and its dependencies must live beside each other on disk
|
106
|
+
- git-multirepo should be considered beta at the moment. Suggestions and contributions are welcome.
|
107
|
+
- The project and its dependencies must live beside each other on disk.
|
105
108
|
- Some more commands need to be implemented to facilitate branch-heavy workflows.
|
106
109
|
- You must (ideally) install the tool on your CI server: `gem install git-multirepo`
|
107
110
|
|
@@ -116,7 +119,6 @@ Here is a quick rundown of commands available to you in git-multirepo:
|
|
116
119
|
| branch | Create and/or checkout a new branch for all repos. |
|
117
120
|
| checkout | Checks out the specified commit or branch of the main repo and checks out matching versions of all dependencies. |
|
118
121
|
| clone | Clones the specified repository in a subfolder, then installs it. |
|
119
|
-
| edit | Opens the .multirepo file in the default text editor. |
|
120
122
|
| fetch | Performs a git fetch on all dependencies. |
|
121
123
|
| install | Clones and checks out dependencies as defined in the version-controlled multirepo metadata files and installs git-multirepo's local git hooks. |
|
122
124
|
| open | Opens all dependencies in the current OS's file explorer. |
|
data/bin/multi
CHANGED
data/lib/commands.rb
CHANGED
@@ -3,7 +3,6 @@ require_relative "multirepo/commands/add-command"
|
|
3
3
|
require_relative "multirepo/commands/branch-command"
|
4
4
|
require_relative "multirepo/commands/checkout-command"
|
5
5
|
require_relative "multirepo/commands/clone-command"
|
6
|
-
require_relative "multirepo/commands/edit-command"
|
7
6
|
require_relative "multirepo/commands/fetch-command"
|
8
7
|
require_relative "multirepo/commands/init-command"
|
9
8
|
require_relative "multirepo/commands/install-command"
|
data/lib/info.rb
CHANGED
@@ -47,61 +47,73 @@ module MultiRepo
|
|
47
47
|
CheckoutMode::AS_LOCK
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
main_repo = Repo.new(".")
|
51
|
+
initial_revision = main_repo.current_branch || main_repo.head_hash
|
52
|
+
|
53
|
+
main_repo_checkout_step(main_repo, initial_revision, @ref)
|
54
|
+
ensure_dependencies_clean_step(initial_revision)
|
55
|
+
dependencies_checkout_step(mode, @ref)
|
51
56
|
|
52
57
|
Console.log_step("Done!")
|
53
58
|
rescue MultiRepoException => e
|
54
59
|
Console.log_error(e.message)
|
55
60
|
end
|
56
|
-
|
57
|
-
def
|
58
|
-
|
59
|
-
initial_revision = main_repo.current_branch || main_repo.head_hash
|
60
|
-
|
61
|
+
|
62
|
+
def main_repo_checkout_step(main_repo, initial_revision, ref)
|
63
|
+
# Make sure the main repo is clean before attempting a checkout
|
61
64
|
unless main_repo.is_clean?
|
62
65
|
raise MultiRepoException, "Can't checkout #{ref} because the main repo contains uncommitted changes"
|
63
66
|
end
|
64
67
|
|
68
|
+
# Checkout the specified ref
|
65
69
|
unless main_repo.checkout(ref)
|
66
70
|
raise MultiRepoException, "Couldn't perform checkout of main repo #{ref}!"
|
67
71
|
end
|
68
72
|
|
69
73
|
Console.log_substep("Checked out main repo #{ref}")
|
70
74
|
|
71
|
-
|
75
|
+
# After checkout, make sure we're working with a multirepo-enabled ref
|
76
|
+
unless Utils.is_multirepo_enabled(".")
|
72
77
|
main_repo.checkout(initial_revision)
|
73
|
-
raise MultiRepoException, "
|
78
|
+
raise MultiRepoException, "This revision is not managed by multirepo. Checkout reverted."
|
74
79
|
end
|
75
|
-
|
80
|
+
end
|
81
|
+
|
82
|
+
def ensure_dependencies_clean_step(initial_revision)
|
76
83
|
unless Utils.ensure_dependencies_clean(ConfigFile.load)
|
77
84
|
main_repo.checkout(initial_revision)
|
78
|
-
raise MultiRepoException, "
|
85
|
+
raise MultiRepoException, "Checkout reverted."
|
79
86
|
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def dependencies_checkout_step(mode, ref = nil)
|
90
|
+
config_entries = ConfigFile.load # Post-main-repo checkout config entries might be different than pre-checkout
|
91
|
+
LockFile.load.each { |lock_entry| perform_dependency_checkout(config_entries, lock_entry, ref, mode) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def perform_dependency_checkout(config_entries, lock_entry, ref, mode)
|
95
|
+
# Find the config entry that matches the given lock entry
|
96
|
+
config_entry = config_entries.select{ |config_entry| config_entry.id == lock_entry.id }.first
|
80
97
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
#
|
100
|
-
if config_entry.repo.checkout(revision)
|
101
|
-
Console.log_substep("Checked out #{lock_entry.name} #{revision}")
|
102
|
-
else
|
103
|
-
raise MultiRepoException, "Couldn't check out the appropriate version of dependency #{lock_entry.name}"
|
104
|
-
end
|
98
|
+
# Make sure the repo exists on disk, and clone it if it doesn't
|
99
|
+
# (in case the checked-out revision had an additional dependency)
|
100
|
+
unless config_entry.repo.exists?
|
101
|
+
Console.log_substep("Cloning missing dependency '#{config_entry.path}' from #{config_entry.url}")
|
102
|
+
config_entry.repo.clone(config_entry.url)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Find out the proper revision to checkout based on the checkout mode
|
106
|
+
revision = case mode
|
107
|
+
when CheckoutMode::AS_LOCK; lock_entry.head
|
108
|
+
when CheckoutMode::LATEST; lock_entry.branch
|
109
|
+
when CheckoutMode::EXACT; ref
|
110
|
+
end
|
111
|
+
|
112
|
+
# Checkout!
|
113
|
+
if config_entry.repo.checkout(revision)
|
114
|
+
Console.log_substep("Checked out #{lock_entry.name} #{revision}")
|
115
|
+
else
|
116
|
+
raise MultiRepoException, "Couldn't check out the appropriate version of dependency #{lock_entry.name}"
|
105
117
|
end
|
106
118
|
end
|
107
119
|
end
|
@@ -19,7 +19,7 @@ module MultiRepo
|
|
19
19
|
def initialize(argv)
|
20
20
|
@url = argv.shift_argument
|
21
21
|
@name = argv.shift_argument
|
22
|
-
@ref = argv.shift_argument
|
22
|
+
@ref = argv.shift_argument || "master"
|
23
23
|
super
|
24
24
|
end
|
25
25
|
|
@@ -35,20 +35,33 @@ module MultiRepo
|
|
35
35
|
raise MultiRepoException, "A directory named #{@name} already exists" if Dir.exists?(@name)
|
36
36
|
|
37
37
|
main_repo_path = "#{@name}/#{@name}"
|
38
|
-
|
39
|
-
FileUtils.mkpath(main_repo_path)
|
40
|
-
|
41
38
|
main_repo = Repo.new(main_repo_path)
|
39
|
+
|
40
|
+
# Recursively create the directory where we'll clone the main repo
|
41
|
+
FileUtils.mkpath(main_repo_path)
|
42
|
+
|
43
|
+
# Clone the specified remote in the just-created directory
|
42
44
|
raise MultiRepoException, "Could not clone repo from #{@url}" unless main_repo.clone(@url)
|
43
45
|
|
46
|
+
# Checkout the specified main repo ref so that install reads the proper config file
|
47
|
+
unless main_repo.checkout(@ref)
|
48
|
+
raise MultiRepoException, "Couldn't perform checkout of main repo #{@ref}!"
|
49
|
+
end
|
50
|
+
|
51
|
+
Console.log_substep("Checked out main repo #{@ref}")
|
52
|
+
|
53
|
+
# Make sure the ref we just checked out is multirepo-enabled
|
54
|
+
unless Utils.is_multirepo_enabled(main_repo_path)
|
55
|
+
raise MultiRepoException, "Ref #{@ref} is not multirepo-enabled"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Install
|
44
59
|
original_path = Dir.pwd
|
45
60
|
Dir.chdir(main_repo_path)
|
46
|
-
|
47
61
|
install_command = InstallCommand.new(CLAide::ARGV.new([]))
|
48
|
-
install_command.
|
49
|
-
|
62
|
+
install_command.install_dependencies_step
|
50
63
|
Dir.chdir(original_path)
|
51
|
-
|
64
|
+
|
52
65
|
Console.log_step("Done!")
|
53
66
|
rescue MultiRepoException => e
|
54
67
|
Console.log_error(e.message)
|
@@ -9,11 +9,11 @@ module MultiRepo
|
|
9
9
|
self.summary = "Clones and checks out dependencies as defined in the version-controlled multirepo metadata files and installs git-multirepo's local git hooks."
|
10
10
|
|
11
11
|
def self.options
|
12
|
-
[['
|
12
|
+
[['-hooks', 'Only install local git hooks.']].concat(super)
|
13
13
|
end
|
14
14
|
|
15
15
|
def initialize(argv)
|
16
|
-
@
|
16
|
+
@hooks = argv.flag?("hooks")
|
17
17
|
super
|
18
18
|
end
|
19
19
|
|
@@ -21,27 +21,35 @@ module MultiRepo
|
|
21
21
|
validate_in_work_tree
|
22
22
|
ensure_multirepo_initialized
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
if @hooks
|
25
|
+
Console.log_step("Installing hooks in main repo and all dependencies...")
|
26
|
+
install_hooks_step
|
27
|
+
else
|
28
|
+
Console.log_step("Cloning dependencies and installing hooks...")
|
29
|
+
install_dependencies_step
|
30
|
+
end
|
27
31
|
|
28
32
|
Console.log_step("Done!")
|
29
33
|
rescue MultiRepoException => e
|
30
34
|
Console.log_error(e.message)
|
31
35
|
end
|
32
36
|
|
33
|
-
def
|
37
|
+
def install_dependencies_step
|
38
|
+
# Read config entries as-is on disk, without prior checkout
|
34
39
|
config_entries = ConfigFile.load
|
35
|
-
|
36
40
|
Console.log_substep("Installing #{config_entries.count} dependencies...");
|
37
41
|
|
38
|
-
# Clone or fetch all configured dependencies
|
42
|
+
# Clone or fetch all configured dependencies to make sure nothing is missing locally
|
39
43
|
config_entries.each { |entry| clone_or_fetch(entry) }
|
40
44
|
|
41
45
|
# Checkout the appropriate branches as specified in the lock file
|
42
46
|
checkout_command = CheckoutCommand.new(CLAide::ARGV.new([]))
|
43
|
-
checkout_command.
|
47
|
+
checkout_command.dependencies_checkout_step(CheckoutCommand::CheckoutMode::LATEST)
|
44
48
|
|
49
|
+
install_hooks_step
|
50
|
+
end
|
51
|
+
|
52
|
+
def install_hooks_step
|
45
53
|
install_hooks
|
46
54
|
Console.log_substep("Installed git hooks in main repo")
|
47
55
|
|
@@ -69,12 +77,6 @@ module MultiRepo
|
|
69
77
|
raise MultiRepoException, "Could not clone remote #{entry.url}" unless entry.repo.clone(entry.url)
|
70
78
|
end
|
71
79
|
|
72
|
-
def checkout_branch(entry)
|
73
|
-
branch = entry.repo.branch(entry.branch);
|
74
|
-
raise MultiRepoException, "Could not checkout branch #{branch.name}" unless branch.checkout
|
75
|
-
Console.log_substep("Checked out branch #{branch.name} -> origin/#{branch.name}")
|
76
|
-
end
|
77
|
-
|
78
80
|
# Validation
|
79
81
|
|
80
82
|
def check_repo_validity(entry)
|
@@ -24,11 +24,6 @@ module MultiRepo
|
|
24
24
|
|
25
25
|
Console.log_step("Updating...")
|
26
26
|
|
27
|
-
install_hooks
|
28
|
-
Console.log_substep("Installed git hooks in main repo")
|
29
|
-
|
30
|
-
install_hooks_in_multirepo_enabled_dependencies
|
31
|
-
|
32
27
|
dependencies_clean = Utils.ensure_dependencies_clean(ConfigFile.load)
|
33
28
|
if dependencies_clean
|
34
29
|
LockFile.update
|
@@ -8,7 +8,8 @@ module MultiRepo
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.is_multirepo_enabled(path)
|
11
|
-
File.exists?(File.join(path, ".multirepo"))
|
11
|
+
File.exists?(File.join(path, ".multirepo")) &&
|
12
|
+
File.exists?(File.join(path, ".multirepo.lock"))
|
12
13
|
end
|
13
14
|
|
14
15
|
def self.install_hook(name, path)
|
@@ -22,21 +23,25 @@ module MultiRepo
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def self.ensure_dependencies_clean(config_entries)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
clean = true
|
27
|
+
config_entries.each do |e|
|
28
|
+
next unless e.repo.exists?
|
29
|
+
dependency_clean = e.repo.is_clean?
|
30
|
+
clean &= dependency_clean
|
31
|
+
Console.log_info("Dependency '#{e.repo.path}' is clean") if dependency_clean
|
32
|
+
Console.log_warning("Dependency '#{e.repo.path}' contains uncommitted changes") unless dependency_clean
|
31
33
|
end
|
34
|
+
return clean
|
32
35
|
end
|
33
36
|
|
34
37
|
def self.ensure_working_copies_clean(repos)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
clean = true
|
39
|
+
repos.each do |repo|
|
40
|
+
dependency_clean = e.repo.is_clean?
|
41
|
+
clean &= dependency_clean
|
42
|
+
Console.log_warning("Repo '#{repo.path}' contains uncommitted changes") unless dependency_clean
|
39
43
|
end
|
44
|
+
return clean
|
40
45
|
end
|
41
46
|
|
42
47
|
def self.convert_to_windows_path(unix_path)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-multirepo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michaël Fortin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -127,7 +127,6 @@ files:
|
|
127
127
|
- lib/multirepo/commands/checkout-command.rb
|
128
128
|
- lib/multirepo/commands/clone-command.rb
|
129
129
|
- lib/multirepo/commands/command.rb
|
130
|
-
- lib/multirepo/commands/edit-command.rb
|
131
130
|
- lib/multirepo/commands/fetch-command.rb
|
132
131
|
- lib/multirepo/commands/init-command.rb
|
133
132
|
- lib/multirepo/commands/install-command.rb
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require "os"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class EditCommand < Command
|
5
|
-
self.command = "edit"
|
6
|
-
self.summary = "Opens the .multirepo file in the default text editor."
|
7
|
-
|
8
|
-
def run
|
9
|
-
validate_in_work_tree
|
10
|
-
ensure_multirepo_initialized
|
11
|
-
|
12
|
-
if OS.posix?
|
13
|
-
editor = `echo ${FCEDIT:-${VISUAL:-${EDITOR:-vi}}}`.strip
|
14
|
-
system(editor, ".multirepo")
|
15
|
-
elsif OS.windows?
|
16
|
-
raise MultiRepoException, "The edit command is not implemented on Window yet."
|
17
|
-
end
|
18
|
-
rescue MultiRepoException => e
|
19
|
-
Console.log_error(e.message)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|