Subrepositories are quite an important things if you have any bigger project, where you can extract some libraries, modules, parts or any other such things. We have chosen Mercurial for version control, because it distributed (svn suxx ass), easy to use, and have good cross-platform support. Until version 1.3 it did not have any support for subrepositories, now it has one. It is far from perfect, but still much better than nothing. And I am sure it will get better, or eventually great.
But for the time I have made quite simple Rakefile to help with subrepos. It works fine also with Mercurial versions less than 1.3. To use it you must have Ruby and gems: rake, term-ansicolor installed. Script assumes that you have subdirectories which are Mercurial repositiories and issues commands on each of them.
rake -T
will give you list of available tasks:
- hg - generic task. You can invoke it like:
CMD=status rake hg
and it will invoke CMD on every repository. In this case it will display status. - pull, push, status - does what the name says.
- update - does pull -u.
- rebase - does pull –rebase. You must have
hgext.rebase=
enabled for it to work. - tag - invoked
rake tag name=0.1
will tag each repository with tag 0.1. - upto - invoked
rake upto rev=0.2
will dohg up -r 0.2
. It makes sense with branches and tags, not so much with revisions, because each subrepo have its own history ;-). - commit - if you have main repository, that contains all the others (as when you use Mercurial subrepo support) it will read commit messages from all the subrepos since last commit to the main repo and copy them into clipboard (works on a Mac only, I think).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
begin
require 'term/ansicolor'
class String
include Term::ANSIColor
end
rescue LoadError => e
STDERR.puts "Please install gem term-ansicolor to use this rakefile."
exit(1)
end
@repos = Dir["**/.hg"].map { |f| f.sub(/.hg$/, "") }
def on_repos(cmd)
@repos.each do |project|
begin
puts "= #{project.red} (#{cmd.yellow})"
system "cd #{project}; #{cmd}"
rescue => e
puts "Failed because: #{e}".red
end
end
end
desc "Invokes any hg command on every repo. Provide CMD=command env variable."
task :hg do
if ENV['CMD'].nil?
puts "Missing rev parameter"
else
on_repos("hg #{ENV['CMD']}")
end
end
desc "Rebase"
task :rebase do
on_repos("hg pull --rebase")
end
desc "Pull"
task :pull do
on_repos("hg pull")
end
desc "Pull -u"
task :update do
on_repos("hg pull -u")
end
desc "Status"
task :status do
on_repos("hg status")
end
desc "Push"
task :push do
on_repos("hg push")
end
desc "Tag repos. Provide name=tag_name param"
task :tag do |t, args|
if args.name.nil?
puts "Missing name parameter"
else
on_repos("hg tag #{args.name}")
end
end
desc "Update all repos to some revision. Provide rev=revision parameter."
task :upto do |t, args|
if args.rev.nil?
puts "Missing rev parameter"
else
on_repos("hg update -C #{args.name}")
end
end
desc "Commits main repository and adds commits messages from every subrepo."
task :commit do
require 'time'
last_date = Time.parse(%x{hg tip --template '{date|isodate}'}) + 60
date = last_date.strftime("%Y-%m-%d %H:%M")
out = @repos.reject { |r| File.basename(r) == "itiner" }.map do |r|
log = %x{cd #{r} && hg log -d '>#{date}' --template="== {desc}\n"}.strip
log.empty? ? nil : "= #{File.basename r}\n#{log}"
end
msg = out.compact.join("\n\n").strip
# mac only?
IO.popen('pbcopy', 'w') do |pipe|
pipe.print(msg)
end
system "hg commit && hg push"
end