##// END OF EJS Templates
merge with crew-stable
Dirkjan Ochtman -
r9219:3f650f6a merge default
parent child Browse files
Show More
@@ -1,15 +1,16 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
@@ -1,27 +1,28 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
@@ -1,148 +1,147 b''
1 # fetch.py - pull and merge remote changes
1 # fetch.py - pull and merge remote changes
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 '''pull, update and merge in one command'''
8 '''pull, update and merge in one command'''
9
9
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial.node import nullid, short
11 from mercurial.node import nullid, short
12 from mercurial import commands, cmdutil, hg, util, url, error
12 from mercurial import commands, cmdutil, hg, util, url, error
13 from mercurial.lock import release
13 from mercurial.lock import release
14
14
15 def fetch(ui, repo, source='default', **opts):
15 def fetch(ui, repo, source='default', **opts):
16 '''pull changes from a remote repository, merge new changes if needed.
16 '''pull changes from a remote repository, merge new changes if needed.
17
17
18 This finds all changes from the repository at the specified path or URL
18 This finds all changes from the repository at the specified path or URL
19 and adds them to the local repository.
19 and adds them to the local repository.
20
20
21 If the pulled changes add a new branch head, the head is automatically
21 If the pulled changes add a new branch head, the head is automatically
22 merged, and the result of the merge is committed. Otherwise, the working
22 merged, and the result of the merge is committed. Otherwise, the working
23 directory is updated to include the new changes.
23 directory is updated to include the new changes.
24
24
25 When a merge occurs, the newly pulled changes are assumed to be
25 When a merge occurs, the newly pulled changes are assumed to be
26 "authoritative". The head of the new changes is used as the first parent,
26 "authoritative". The head of the new changes is used as the first parent,
27 with local changes as the second. To switch the merge order, use
27 with local changes as the second. To switch the merge order, use
28 --switch-parent.
28 --switch-parent.
29
29
30 See 'hg help dates' for a list of formats valid for -d/--date.
30 See 'hg help dates' for a list of formats valid for -d/--date.
31 '''
31 '''
32
32
33 date = opts.get('date')
33 date = opts.get('date')
34 if date:
34 if date:
35 opts['date'] = util.parsedate(date)
35 opts['date'] = util.parsedate(date)
36
36
37 parent, p2 = repo.dirstate.parents()
37 parent, p2 = repo.dirstate.parents()
38 branch = repo.dirstate.branch()
38 branch = repo.dirstate.branch()
39 branchnode = repo.branchtags().get(branch)
39 branchnode = repo.branchtags().get(branch)
40 if parent != branchnode:
40 if parent != branchnode:
41 raise util.Abort(_('working dir not at branch tip '
41 raise util.Abort(_('working dir not at branch tip '
42 '(use "hg update" to check out branch tip)'))
42 '(use "hg update" to check out branch tip)'))
43
43
44 if p2 != nullid:
44 if p2 != nullid:
45 raise util.Abort(_('outstanding uncommitted merge'))
45 raise util.Abort(_('outstanding uncommitted merge'))
46
46
47 wlock = lock = None
47 wlock = lock = None
48 try:
48 try:
49 wlock = repo.wlock()
49 wlock = repo.wlock()
50 lock = repo.lock()
50 lock = repo.lock()
51 mod, add, rem, del_ = repo.status()[:4]
51 mod, add, rem, del_ = repo.status()[:4]
52
52
53 if mod or add or rem:
53 if mod or add or rem:
54 raise util.Abort(_('outstanding uncommitted changes'))
54 raise util.Abort(_('outstanding uncommitted changes'))
55 if del_:
55 if del_:
56 raise util.Abort(_('working directory is missing some files'))
56 raise util.Abort(_('working directory is missing some files'))
57 bheads = repo.branchheads(branch)
57 bheads = repo.branchheads(branch)
58 bheads = [head for head in bheads if len(repo[head].children()) == 0]
58 bheads = [head for head in bheads if len(repo[head].children()) == 0]
59 if len(bheads) > 1:
59 if len(bheads) > 1:
60 raise util.Abort(_('multiple heads in this branch '
60 raise util.Abort(_('multiple heads in this branch '
61 '(use "hg heads ." and "hg merge" to merge)'))
61 '(use "hg heads ." and "hg merge" to merge)'))
62
62
63 other = hg.repository(cmdutil.remoteui(repo, opts),
63 other = hg.repository(cmdutil.remoteui(repo, opts),
64 ui.expandpath(source))
64 ui.expandpath(source))
65 ui.status(_('pulling from %s\n') %
65 ui.status(_('pulling from %s\n') %
66 url.hidepassword(ui.expandpath(source)))
66 url.hidepassword(ui.expandpath(source)))
67 revs = None
67 revs = None
68 if opts['rev']:
68 if opts['rev']:
69 try:
69 try:
70 revs = [other.lookup(rev) for rev in opts['rev']]
70 revs = [other.lookup(rev) for rev in opts['rev']]
71 except error.CapabilityError:
71 except error.CapabilityError:
72 err = _("Other repository doesn't support revision lookup, "
72 err = _("Other repository doesn't support revision lookup, "
73 "so a rev cannot be specified.")
73 "so a rev cannot be specified.")
74 raise util.Abort(err)
74 raise util.Abort(err)
75
75
76 # Are there any changes at all?
76 # Are there any changes at all?
77 modheads = repo.pull(other, heads=revs)
77 modheads = repo.pull(other, heads=revs)
78 if modheads == 0:
78 if modheads == 0:
79 return 0
79 return 0
80
80
81 # Is this a simple fast-forward along the current branch?
81 # Is this a simple fast-forward along the current branch?
82 newheads = repo.branchheads(branch)
82 newheads = repo.branchheads(branch)
83 newheads = [head for head in newheads if len(repo[head].children()) == 0]
83 newheads = [head for head in newheads if len(repo[head].children()) == 0]
84 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
84 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
85 if len(newheads) == 1:
85 if len(newheads) == 1:
86 if newchildren[0] != parent:
86 if newchildren[0] != parent:
87 return hg.clean(repo, newchildren[0])
87 return hg.clean(repo, newchildren[0])
88 else:
88 else:
89 return
89 return
90
90
91 # Are there more than one additional branch heads?
91 # Are there more than one additional branch heads?
92 newchildren = [n for n in newchildren if n != parent]
92 newchildren = [n for n in newchildren if n != parent]
93 newparent = parent
93 newparent = parent
94 if newchildren:
94 if newchildren:
95 newparent = newchildren[0]
95 newparent = newchildren[0]
96 hg.clean(repo, newparent)
96 hg.clean(repo, newparent)
97 newheads = [n for n in newheads if n != newparent]
97 newheads = [n for n in newheads if n != newparent]
98 if len(newheads) > 1:
98 if len(newheads) > 1:
99 ui.status(_('not merging with %d other new branch heads '
99 ui.status(_('not merging with %d other new branch heads '
100 '(use "hg heads ." and "hg merge" to merge them)\n') %
100 '(use "hg heads ." and "hg merge" to merge them)\n') %
101 (len(newheads) - 1))
101 (len(newheads) - 1))
102 return
102 return
103
103
104 # Otherwise, let's merge.
104 # Otherwise, let's merge.
105 err = False
105 err = False
106 if newheads:
106 if newheads:
107 # By default, we consider the repository we're pulling
107 # By default, we consider the repository we're pulling
108 # *from* as authoritative, so we merge our changes into
108 # *from* as authoritative, so we merge our changes into
109 # theirs.
109 # theirs.
110 if opts['switch_parent']:
110 if opts['switch_parent']:
111 firstparent, secondparent = newparent, newheads[0]
111 firstparent, secondparent = newparent, newheads[0]
112 else:
112 else:
113 firstparent, secondparent = newheads[0], newparent
113 firstparent, secondparent = newheads[0], newparent
114 ui.status(_('updating to %d:%s\n') %
114 ui.status(_('updating to %d:%s\n') %
115 (repo.changelog.rev(firstparent),
115 (repo.changelog.rev(firstparent),
116 short(firstparent)))
116 short(firstparent)))
117 hg.clean(repo, firstparent)
117 hg.clean(repo, firstparent)
118 ui.status(_('merging with %d:%s\n') %
118 ui.status(_('merging with %d:%s\n') %
119 (repo.changelog.rev(secondparent), short(secondparent)))
119 (repo.changelog.rev(secondparent), short(secondparent)))
120 err = hg.merge(repo, secondparent, remind=False)
120 err = hg.merge(repo, secondparent, remind=False)
121
121
122 if not err:
122 if not err:
123 # we don't translate commit messages
123 # we don't translate commit messages
124 message = (cmdutil.logmessage(opts) or
124 message = (cmdutil.logmessage(opts) or
125 ('Automated merge with %s' %
125 ('Automated merge with %s' %
126 url.removeauth(other.url())))
126 url.removeauth(other.url())))
127 editor = cmdutil.commiteditor
127 editor = cmdutil.commiteditor
128 if opts.get('force_editor') or opts.get('edit'):
128 if opts.get('force_editor') or opts.get('edit'):
129 editor = cmdutil.commitforceeditor
129 editor = cmdutil.commitforceeditor
130 n = repo.commit(message, opts['user'], opts['date'],
130 n = repo.commit(message, opts['user'], opts['date'], editor=editor)
131 force=True, editor=editor)
132 ui.status(_('new changeset %d:%s merges remote changes '
131 ui.status(_('new changeset %d:%s merges remote changes '
133 'with local\n') % (repo.changelog.rev(n),
132 'with local\n') % (repo.changelog.rev(n),
134 short(n)))
133 short(n)))
135
134
136 finally:
135 finally:
137 release(lock, wlock)
136 release(lock, wlock)
138
137
139 cmdtable = {
138 cmdtable = {
140 'fetch':
139 'fetch':
141 (fetch,
140 (fetch,
142 [('r', 'rev', [], _('a specific revision you would like to pull')),
141 [('r', 'rev', [], _('a specific revision you would like to pull')),
143 ('e', 'edit', None, _('edit commit message')),
142 ('e', 'edit', None, _('edit commit message')),
144 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
143 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
145 ('', 'switch-parent', None, _('switch parents when merging')),
144 ('', 'switch-parent', None, _('switch parents when merging')),
146 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
145 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
147 _('hg fetch [SOURCE]')),
146 _('hg fetch [SOURCE]')),
148 }
147 }
@@ -1,544 +1,544 b''
1 # keyword.py - $Keyword$ expansion for Mercurial
1 # keyword.py - $Keyword$ expansion for Mercurial
2 #
2 #
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7 #
7 #
8 # $Id$
8 # $Id$
9 #
9 #
10 # Keyword expansion hack against the grain of a DSCM
10 # Keyword expansion hack against the grain of a DSCM
11 #
11 #
12 # There are many good reasons why this is not needed in a distributed
12 # There are many good reasons why this is not needed in a distributed
13 # SCM, still it may be useful in very small projects based on single
13 # SCM, still it may be useful in very small projects based on single
14 # files (like LaTeX packages), that are mostly addressed to an
14 # files (like LaTeX packages), that are mostly addressed to an
15 # audience not running a version control system.
15 # audience not running a version control system.
16 #
16 #
17 # For in-depth discussion refer to
17 # For in-depth discussion refer to
18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
19 #
19 #
20 # Keyword expansion is based on Mercurial's changeset template mappings.
20 # Keyword expansion is based on Mercurial's changeset template mappings.
21 #
21 #
22 # Binary files are not touched.
22 # Binary files are not touched.
23 #
23 #
24 # Files to act upon/ignore are specified in the [keyword] section.
24 # Files to act upon/ignore are specified in the [keyword] section.
25 # Customized keyword template mappings in the [keywordmaps] section.
25 # Customized keyword template mappings in the [keywordmaps] section.
26 #
26 #
27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
28
28
29 '''expand keywords in tracked files
29 '''expand keywords in tracked files
30
30
31 This extension expands RCS/CVS-like or self-customized $Keywords$ in tracked
31 This extension expands RCS/CVS-like or self-customized $Keywords$ in tracked
32 text files selected by your configuration.
32 text files selected by your configuration.
33
33
34 Keywords are only expanded in local repositories and not stored in the change
34 Keywords are only expanded in local repositories and not stored in the change
35 history. The mechanism can be regarded as a convenience for the current user
35 history. The mechanism can be regarded as a convenience for the current user
36 or for archive distribution.
36 or for archive distribution.
37
37
38 Configuration is done in the [keyword] and [keywordmaps] sections of hgrc
38 Configuration is done in the [keyword] and [keywordmaps] sections of hgrc
39 files.
39 files.
40
40
41 Example::
41 Example::
42
42
43 [keyword]
43 [keyword]
44 # expand keywords in every python file except those matching "x*"
44 # expand keywords in every python file except those matching "x*"
45 **.py =
45 **.py =
46 x* = ignore
46 x* = ignore
47
47
48 NOTE: the more specific you are in your filename patterns the less you lose
48 NOTE: the more specific you are in your filename patterns the less you lose
49 speed in huge repositories.
49 speed in huge repositories.
50
50
51 For [keywordmaps] template mapping and expansion demonstration and control run
51 For [keywordmaps] template mapping and expansion demonstration and control run
52 "hg kwdemo".
52 "hg kwdemo".
53
53
54 An additional date template filter {date|utcdate} is provided.
54 An additional date template filter {date|utcdate} is provided.
55
55
56 The default template mappings (view with "hg kwdemo -d") can be replaced with
56 The default template mappings (view with "hg kwdemo -d") can be replaced with
57 customized keywords and templates. Again, run "hg kwdemo" to control the
57 customized keywords and templates. Again, run "hg kwdemo" to control the
58 results of your config changes.
58 results of your config changes.
59
59
60 Before changing/disabling active keywords, run "hg kwshrink" to avoid the risk
60 Before changing/disabling active keywords, run "hg kwshrink" to avoid the risk
61 of inadvertently storing expanded keywords in the change history.
61 of inadvertently storing expanded keywords in the change history.
62
62
63 To force expansion after enabling it, or a configuration change, run "hg
63 To force expansion after enabling it, or a configuration change, run "hg
64 kwexpand".
64 kwexpand".
65
65
66 Also, when committing with the record extension or using mq's qrecord, be
66 Also, when committing with the record extension or using mq's qrecord, be
67 aware that keywords cannot be updated. Again, run "hg kwexpand" on the files
67 aware that keywords cannot be updated. Again, run "hg kwexpand" on the files
68 in question to update keyword expansions after all changes have been checked
68 in question to update keyword expansions after all changes have been checked
69 in.
69 in.
70
70
71 Expansions spanning more than one line and incremental expansions, like CVS'
71 Expansions spanning more than one line and incremental expansions, like CVS'
72 $Log$, are not supported. A keyword template map "Log = {desc}" expands to the
72 $Log$, are not supported. A keyword template map "Log = {desc}" expands to the
73 first line of the changeset description.
73 first line of the changeset description.
74 '''
74 '''
75
75
76 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
76 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
77 from mercurial import patch, localrepo, templater, templatefilters, util, match
77 from mercurial import patch, localrepo, templater, templatefilters, util, match
78 from mercurial.hgweb import webcommands
78 from mercurial.hgweb import webcommands
79 from mercurial.lock import release
79 from mercurial.lock import release
80 from mercurial.node import nullid
80 from mercurial.node import nullid
81 from mercurial.i18n import _
81 from mercurial.i18n import _
82 import re, shutil, tempfile, time
82 import re, shutil, tempfile, time
83
83
84 commands.optionalrepo += ' kwdemo'
84 commands.optionalrepo += ' kwdemo'
85
85
86 # hg commands that do not act on keywords
86 # hg commands that do not act on keywords
87 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
87 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
88 ' log outgoing push rename rollback tip verify'
88 ' log outgoing push rename rollback tip verify'
89 ' convert email glog')
89 ' convert email glog')
90
90
91 # hg commands that trigger expansion only when writing to working dir,
91 # hg commands that trigger expansion only when writing to working dir,
92 # not when reading filelog, and unexpand when reading from working dir
92 # not when reading filelog, and unexpand when reading from working dir
93 restricted = 'merge record resolve qfold qimport qnew qpush qrefresh qrecord'
93 restricted = 'merge record resolve qfold qimport qnew qpush qrefresh qrecord'
94
94
95 def utcdate(date):
95 def utcdate(date):
96 '''Returns hgdate in cvs-like UTC format.'''
96 '''Returns hgdate in cvs-like UTC format.'''
97 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
97 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
98
98
99 # make keyword tools accessible
99 # make keyword tools accessible
100 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
100 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
101
101
102
102
103 class kwtemplater(object):
103 class kwtemplater(object):
104 '''
104 '''
105 Sets up keyword templates, corresponding keyword regex, and
105 Sets up keyword templates, corresponding keyword regex, and
106 provides keyword substitution functions.
106 provides keyword substitution functions.
107 '''
107 '''
108 templates = {
108 templates = {
109 'Revision': '{node|short}',
109 'Revision': '{node|short}',
110 'Author': '{author|user}',
110 'Author': '{author|user}',
111 'Date': '{date|utcdate}',
111 'Date': '{date|utcdate}',
112 'RCSFile': '{file|basename},v',
112 'RCSFile': '{file|basename},v',
113 'Source': '{root}/{file},v',
113 'Source': '{root}/{file},v',
114 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
114 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
115 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
115 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
116 }
116 }
117
117
118 def __init__(self, ui, repo):
118 def __init__(self, ui, repo):
119 self.ui = ui
119 self.ui = ui
120 self.repo = repo
120 self.repo = repo
121 self.match = match.match(repo.root, '', [],
121 self.match = match.match(repo.root, '', [],
122 kwtools['inc'], kwtools['exc'])
122 kwtools['inc'], kwtools['exc'])
123 self.restrict = kwtools['hgcmd'] in restricted.split()
123 self.restrict = kwtools['hgcmd'] in restricted.split()
124
124
125 kwmaps = self.ui.configitems('keywordmaps')
125 kwmaps = self.ui.configitems('keywordmaps')
126 if kwmaps: # override default templates
126 if kwmaps: # override default templates
127 self.templates = dict((k, templater.parsestring(v, False))
127 self.templates = dict((k, templater.parsestring(v, False))
128 for k, v in kwmaps)
128 for k, v in kwmaps)
129 escaped = map(re.escape, self.templates.keys())
129 escaped = map(re.escape, self.templates.keys())
130 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
130 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
131 self.re_kw = re.compile(kwpat)
131 self.re_kw = re.compile(kwpat)
132
132
133 templatefilters.filters['utcdate'] = utcdate
133 templatefilters.filters['utcdate'] = utcdate
134 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
134 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
135 False, None, '', False)
135 False, None, '', False)
136
136
137 def substitute(self, data, path, ctx, subfunc):
137 def substitute(self, data, path, ctx, subfunc):
138 '''Replaces keywords in data with expanded template.'''
138 '''Replaces keywords in data with expanded template.'''
139 def kwsub(mobj):
139 def kwsub(mobj):
140 kw = mobj.group(1)
140 kw = mobj.group(1)
141 self.ct.use_template(self.templates[kw])
141 self.ct.use_template(self.templates[kw])
142 self.ui.pushbuffer()
142 self.ui.pushbuffer()
143 self.ct.show(ctx, root=self.repo.root, file=path)
143 self.ct.show(ctx, root=self.repo.root, file=path)
144 ekw = templatefilters.firstline(self.ui.popbuffer())
144 ekw = templatefilters.firstline(self.ui.popbuffer())
145 return '$%s: %s $' % (kw, ekw)
145 return '$%s: %s $' % (kw, ekw)
146 return subfunc(kwsub, data)
146 return subfunc(kwsub, data)
147
147
148 def expand(self, path, node, data):
148 def expand(self, path, node, data):
149 '''Returns data with keywords expanded.'''
149 '''Returns data with keywords expanded.'''
150 if not self.restrict and self.match(path) and not util.binary(data):
150 if not self.restrict and self.match(path) and not util.binary(data):
151 ctx = self.repo.filectx(path, fileid=node).changectx()
151 ctx = self.repo.filectx(path, fileid=node).changectx()
152 return self.substitute(data, path, ctx, self.re_kw.sub)
152 return self.substitute(data, path, ctx, self.re_kw.sub)
153 return data
153 return data
154
154
155 def iskwfile(self, path, flagfunc):
155 def iskwfile(self, path, flagfunc):
156 '''Returns true if path matches [keyword] pattern
156 '''Returns true if path matches [keyword] pattern
157 and is not a symbolic link.
157 and is not a symbolic link.
158 Caveat: localrepository._link fails on Windows.'''
158 Caveat: localrepository._link fails on Windows.'''
159 return self.match(path) and not 'l' in flagfunc(path)
159 return self.match(path) and not 'l' in flagfunc(path)
160
160
161 def overwrite(self, node, expand, files):
161 def overwrite(self, node, expand, files):
162 '''Overwrites selected files expanding/shrinking keywords.'''
162 '''Overwrites selected files expanding/shrinking keywords.'''
163 ctx = self.repo[node]
163 ctx = self.repo[node]
164 mf = ctx.manifest()
164 mf = ctx.manifest()
165 if node is not None: # commit
165 if node is not None: # commit
166 files = [f for f in ctx.files() if f in mf]
166 files = [f for f in ctx.files() if f in mf]
167 notify = self.ui.debug
167 notify = self.ui.debug
168 else: # kwexpand/kwshrink
168 else: # kwexpand/kwshrink
169 notify = self.ui.note
169 notify = self.ui.note
170 candidates = [f for f in files if self.iskwfile(f, ctx.flags)]
170 candidates = [f for f in files if self.iskwfile(f, ctx.flags)]
171 if candidates:
171 if candidates:
172 self.restrict = True # do not expand when reading
172 self.restrict = True # do not expand when reading
173 msg = (expand and _('overwriting %s expanding keywords\n')
173 msg = (expand and _('overwriting %s expanding keywords\n')
174 or _('overwriting %s shrinking keywords\n'))
174 or _('overwriting %s shrinking keywords\n'))
175 for f in candidates:
175 for f in candidates:
176 fp = self.repo.file(f)
176 fp = self.repo.file(f)
177 data = fp.read(mf[f])
177 data = fp.read(mf[f])
178 if util.binary(data):
178 if util.binary(data):
179 continue
179 continue
180 if expand:
180 if expand:
181 if node is None:
181 if node is None:
182 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
182 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
183 data, found = self.substitute(data, f, ctx,
183 data, found = self.substitute(data, f, ctx,
184 self.re_kw.subn)
184 self.re_kw.subn)
185 else:
185 else:
186 found = self.re_kw.search(data)
186 found = self.re_kw.search(data)
187 if found:
187 if found:
188 notify(msg % f)
188 notify(msg % f)
189 self.repo.wwrite(f, data, mf.flags(f))
189 self.repo.wwrite(f, data, mf.flags(f))
190 if node is None:
190 if node is None:
191 self.repo.dirstate.normal(f)
191 self.repo.dirstate.normal(f)
192 self.restrict = False
192 self.restrict = False
193
193
194 def shrinktext(self, text):
194 def shrinktext(self, text):
195 '''Unconditionally removes all keyword substitutions from text.'''
195 '''Unconditionally removes all keyword substitutions from text.'''
196 return self.re_kw.sub(r'$\1$', text)
196 return self.re_kw.sub(r'$\1$', text)
197
197
198 def shrink(self, fname, text):
198 def shrink(self, fname, text):
199 '''Returns text with all keyword substitutions removed.'''
199 '''Returns text with all keyword substitutions removed.'''
200 if self.match(fname) and not util.binary(text):
200 if self.match(fname) and not util.binary(text):
201 return self.shrinktext(text)
201 return self.shrinktext(text)
202 return text
202 return text
203
203
204 def shrinklines(self, fname, lines):
204 def shrinklines(self, fname, lines):
205 '''Returns lines with keyword substitutions removed.'''
205 '''Returns lines with keyword substitutions removed.'''
206 if self.match(fname):
206 if self.match(fname):
207 text = ''.join(lines)
207 text = ''.join(lines)
208 if not util.binary(text):
208 if not util.binary(text):
209 return self.shrinktext(text).splitlines(True)
209 return self.shrinktext(text).splitlines(True)
210 return lines
210 return lines
211
211
212 def wread(self, fname, data):
212 def wread(self, fname, data):
213 '''If in restricted mode returns data read from wdir with
213 '''If in restricted mode returns data read from wdir with
214 keyword substitutions removed.'''
214 keyword substitutions removed.'''
215 return self.restrict and self.shrink(fname, data) or data
215 return self.restrict and self.shrink(fname, data) or data
216
216
217 class kwfilelog(filelog.filelog):
217 class kwfilelog(filelog.filelog):
218 '''
218 '''
219 Subclass of filelog to hook into its read, add, cmp methods.
219 Subclass of filelog to hook into its read, add, cmp methods.
220 Keywords are "stored" unexpanded, and processed on reading.
220 Keywords are "stored" unexpanded, and processed on reading.
221 '''
221 '''
222 def __init__(self, opener, kwt, path):
222 def __init__(self, opener, kwt, path):
223 super(kwfilelog, self).__init__(opener, path)
223 super(kwfilelog, self).__init__(opener, path)
224 self.kwt = kwt
224 self.kwt = kwt
225 self.path = path
225 self.path = path
226
226
227 def read(self, node):
227 def read(self, node):
228 '''Expands keywords when reading filelog.'''
228 '''Expands keywords when reading filelog.'''
229 data = super(kwfilelog, self).read(node)
229 data = super(kwfilelog, self).read(node)
230 return self.kwt.expand(self.path, node, data)
230 return self.kwt.expand(self.path, node, data)
231
231
232 def add(self, text, meta, tr, link, p1=None, p2=None):
232 def add(self, text, meta, tr, link, p1=None, p2=None):
233 '''Removes keyword substitutions when adding to filelog.'''
233 '''Removes keyword substitutions when adding to filelog.'''
234 text = self.kwt.shrink(self.path, text)
234 text = self.kwt.shrink(self.path, text)
235 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
235 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
236
236
237 def cmp(self, node, text):
237 def cmp(self, node, text):
238 '''Removes keyword substitutions for comparison.'''
238 '''Removes keyword substitutions for comparison.'''
239 text = self.kwt.shrink(self.path, text)
239 text = self.kwt.shrink(self.path, text)
240 if self.renamed(node):
240 if self.renamed(node):
241 t2 = super(kwfilelog, self).read(node)
241 t2 = super(kwfilelog, self).read(node)
242 return t2 != text
242 return t2 != text
243 return revlog.revlog.cmp(self, node, text)
243 return revlog.revlog.cmp(self, node, text)
244
244
245 def _status(ui, repo, kwt, unknown, *pats, **opts):
245 def _status(ui, repo, kwt, unknown, *pats, **opts):
246 '''Bails out if [keyword] configuration is not active.
246 '''Bails out if [keyword] configuration is not active.
247 Returns status of working directory.'''
247 Returns status of working directory.'''
248 if kwt:
248 if kwt:
249 match = cmdutil.match(repo, pats, opts)
249 match = cmdutil.match(repo, pats, opts)
250 return repo.status(match=match, unknown=unknown, clean=True)
250 return repo.status(match=match, unknown=unknown, clean=True)
251 if ui.configitems('keyword'):
251 if ui.configitems('keyword'):
252 raise util.Abort(_('[keyword] patterns cannot match'))
252 raise util.Abort(_('[keyword] patterns cannot match'))
253 raise util.Abort(_('no [keyword] patterns configured'))
253 raise util.Abort(_('no [keyword] patterns configured'))
254
254
255 def _kwfwrite(ui, repo, expand, *pats, **opts):
255 def _kwfwrite(ui, repo, expand, *pats, **opts):
256 '''Selects files and passes them to kwtemplater.overwrite.'''
256 '''Selects files and passes them to kwtemplater.overwrite.'''
257 if repo.dirstate.parents()[1] != nullid:
257 if repo.dirstate.parents()[1] != nullid:
258 raise util.Abort(_('outstanding uncommitted merge'))
258 raise util.Abort(_('outstanding uncommitted merge'))
259 kwt = kwtools['templater']
259 kwt = kwtools['templater']
260 status = _status(ui, repo, kwt, False, *pats, **opts)
260 status = _status(ui, repo, kwt, False, *pats, **opts)
261 modified, added, removed, deleted = status[:4]
261 modified, added, removed, deleted = status[:4]
262 if modified or added or removed or deleted:
262 if modified or added or removed or deleted:
263 raise util.Abort(_('outstanding uncommitted changes'))
263 raise util.Abort(_('outstanding uncommitted changes'))
264 wlock = lock = None
264 wlock = lock = None
265 try:
265 try:
266 wlock = repo.wlock()
266 wlock = repo.wlock()
267 lock = repo.lock()
267 lock = repo.lock()
268 kwt.overwrite(None, expand, status[6])
268 kwt.overwrite(None, expand, status[6])
269 finally:
269 finally:
270 release(lock, wlock)
270 release(lock, wlock)
271
271
272 def demo(ui, repo, *args, **opts):
272 def demo(ui, repo, *args, **opts):
273 '''print [keywordmaps] configuration and an expansion example
273 '''print [keywordmaps] configuration and an expansion example
274
274
275 Show current, custom, or default keyword template maps and their
275 Show current, custom, or default keyword template maps and their
276 expansions.
276 expansions.
277
277
278 Extend current configuration by specifying maps as arguments and
278 Extend current configuration by specifying maps as arguments and
279 optionally by reading from an additional hgrc file.
279 optionally by reading from an additional hgrc file.
280
280
281 Override current keyword template maps with "default" option.
281 Override current keyword template maps with "default" option.
282 '''
282 '''
283 def demoitems(section, items):
283 def demoitems(section, items):
284 ui.write('[%s]\n' % section)
284 ui.write('[%s]\n' % section)
285 for k, v in items:
285 for k, v in items:
286 ui.write('%s = %s\n' % (k, v))
286 ui.write('%s = %s\n' % (k, v))
287
287
288 msg = 'hg keyword config and expansion example'
288 msg = 'hg keyword config and expansion example'
289 kwstatus = 'current'
289 kwstatus = 'current'
290 fn = 'demo.txt'
290 fn = 'demo.txt'
291 branchname = 'demobranch'
291 branchname = 'demobranch'
292 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
292 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
293 ui.note(_('creating temporary repository at %s\n') % tmpdir)
293 ui.note(_('creating temporary repository at %s\n') % tmpdir)
294 repo = localrepo.localrepository(ui, tmpdir, True)
294 repo = localrepo.localrepository(ui, tmpdir, True)
295 ui.setconfig('keyword', fn, '')
295 ui.setconfig('keyword', fn, '')
296 if args or opts.get('rcfile'):
296 if args or opts.get('rcfile'):
297 kwstatus = 'custom'
297 kwstatus = 'custom'
298 if opts.get('rcfile'):
298 if opts.get('rcfile'):
299 ui.readconfig(opts.get('rcfile'))
299 ui.readconfig(opts.get('rcfile'))
300 if opts.get('default'):
300 if opts.get('default'):
301 kwstatus = 'default'
301 kwstatus = 'default'
302 kwmaps = kwtemplater.templates
302 kwmaps = kwtemplater.templates
303 if ui.configitems('keywordmaps'):
303 if ui.configitems('keywordmaps'):
304 # override maps from optional rcfile
304 # override maps from optional rcfile
305 for k, v in kwmaps.iteritems():
305 for k, v in kwmaps.iteritems():
306 ui.setconfig('keywordmaps', k, v)
306 ui.setconfig('keywordmaps', k, v)
307 elif args:
307 elif args:
308 # simulate hgrc parsing
308 # simulate hgrc parsing
309 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
309 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
310 fp = repo.opener('hgrc', 'w')
310 fp = repo.opener('hgrc', 'w')
311 fp.writelines(rcmaps)
311 fp.writelines(rcmaps)
312 fp.close()
312 fp.close()
313 ui.readconfig(repo.join('hgrc'))
313 ui.readconfig(repo.join('hgrc'))
314 if not opts.get('default'):
314 if not opts.get('default'):
315 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
315 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
316 uisetup(ui)
316 uisetup(ui)
317 reposetup(ui, repo)
317 reposetup(ui, repo)
318 for k, v in ui.configitems('extensions'):
318 for k, v in ui.configitems('extensions'):
319 if k.endswith('keyword'):
319 if k.endswith('keyword'):
320 extension = '%s = %s' % (k, v)
320 extension = '%s = %s' % (k, v)
321 break
321 break
322 ui.status(_('\n\tconfig using %s keyword template maps\n') % kwstatus)
322 ui.status(_('\n\tconfig using %s keyword template maps\n') % kwstatus)
323 ui.write('[extensions]\n%s\n' % extension)
323 ui.write('[extensions]\n%s\n' % extension)
324 demoitems('keyword', ui.configitems('keyword'))
324 demoitems('keyword', ui.configitems('keyword'))
325 demoitems('keywordmaps', kwmaps.iteritems())
325 demoitems('keywordmaps', kwmaps.iteritems())
326 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
326 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
327 repo.wopener(fn, 'w').write(keywords)
327 repo.wopener(fn, 'w').write(keywords)
328 repo.add([fn])
328 repo.add([fn])
329 path = repo.wjoin(fn)
329 path = repo.wjoin(fn)
330 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
330 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
331 ui.note(keywords)
331 ui.note(keywords)
332 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
332 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
333 # silence branch command if not verbose
333 # silence branch command if not verbose
334 quiet = ui.quiet
334 quiet = ui.quiet
335 ui.quiet = not ui.verbose
335 ui.quiet = not ui.verbose
336 commands.branch(ui, repo, branchname)
336 commands.branch(ui, repo, branchname)
337 ui.quiet = quiet
337 ui.quiet = quiet
338 for name, cmd in ui.configitems('hooks'):
338 for name, cmd in ui.configitems('hooks'):
339 if name.split('.', 1)[0].find('commit') > -1:
339 if name.split('.', 1)[0].find('commit') > -1:
340 repo.ui.setconfig('hooks', name, '')
340 repo.ui.setconfig('hooks', name, '')
341 ui.note(_('unhooked all commit hooks\n'))
341 ui.note(_('unhooked all commit hooks\n'))
342 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
342 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
343 repo.commit(text=msg)
343 repo.commit(text=msg)
344 fmt = ui.verbose and ' in %s' % path or ''
344 fmt = ui.verbose and ' in %s' % path or ''
345 ui.status(_('\n\t%s keywords expanded%s\n') % (kwstatus, fmt))
345 ui.status(_('\n\t%s keywords expanded%s\n') % (kwstatus, fmt))
346 ui.write(repo.wread(fn))
346 ui.write(repo.wread(fn))
347 ui.debug(_('\nremoving temporary repository %s\n') % tmpdir)
347 ui.debug(_('\nremoving temporary repository %s\n') % tmpdir)
348 shutil.rmtree(tmpdir, ignore_errors=True)
348 shutil.rmtree(tmpdir, ignore_errors=True)
349
349
350 def expand(ui, repo, *pats, **opts):
350 def expand(ui, repo, *pats, **opts):
351 '''expand keywords in the working directory
351 '''expand keywords in the working directory
352
352
353 Run after (re)enabling keyword expansion.
353 Run after (re)enabling keyword expansion.
354
354
355 kwexpand refuses to run if given files contain local changes.
355 kwexpand refuses to run if given files contain local changes.
356 '''
356 '''
357 # 3rd argument sets expansion to True
357 # 3rd argument sets expansion to True
358 _kwfwrite(ui, repo, True, *pats, **opts)
358 _kwfwrite(ui, repo, True, *pats, **opts)
359
359
360 def files(ui, repo, *pats, **opts):
360 def files(ui, repo, *pats, **opts):
361 '''show files configured for keyword expansion
361 '''show files configured for keyword expansion
362
362
363 List which files in the working directory are matched by the [keyword]
363 List which files in the working directory are matched by the [keyword]
364 configuration patterns.
364 configuration patterns.
365
365
366 Useful to prevent inadvertent keyword expansion and to speed up execution
366 Useful to prevent inadvertent keyword expansion and to speed up execution
367 by including only files that are actual candidates for expansion.
367 by including only files that are actual candidates for expansion.
368
368
369 See "hg help keyword" on how to construct patterns both for inclusion and
369 See "hg help keyword" on how to construct patterns both for inclusion and
370 exclusion of files.
370 exclusion of files.
371
371
372 Use -u/--untracked to list untracked files as well.
372 Use -u/--untracked to list untracked files as well.
373
373
374 With -a/--all and -v/--verbose the codes used to show the status of files
374 With -a/--all and -v/--verbose the codes used to show the status of files
375 are::
375 are::
376
376
377 K = keyword expansion candidate
377 K = keyword expansion candidate
378 k = keyword expansion candidate (untracked)
378 k = keyword expansion candidate (untracked)
379 I = ignored
379 I = ignored
380 i = ignored (untracked)
380 i = ignored (untracked)
381 '''
381 '''
382 kwt = kwtools['templater']
382 kwt = kwtools['templater']
383 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts)
383 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts)
384 modified, added, removed, deleted, unknown, ignored, clean = status
384 modified, added, removed, deleted, unknown, ignored, clean = status
385 files = sorted(modified + added + clean)
385 files = sorted(modified + added + clean)
386 wctx = repo[None]
386 wctx = repo[None]
387 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
387 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
388 kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
388 kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
389 cwd = pats and repo.getcwd() or ''
389 cwd = pats and repo.getcwd() or ''
390 kwfstats = (not opts.get('ignore') and
390 kwfstats = (not opts.get('ignore') and
391 (('K', kwfiles), ('k', kwuntracked),) or ())
391 (('K', kwfiles), ('k', kwuntracked),) or ())
392 if opts.get('all') or opts.get('ignore'):
392 if opts.get('all') or opts.get('ignore'):
393 kwfstats += (('I', [f for f in files if f not in kwfiles]),
393 kwfstats += (('I', [f for f in files if f not in kwfiles]),
394 ('i', [f for f in unknown if f not in kwuntracked]),)
394 ('i', [f for f in unknown if f not in kwuntracked]),)
395 for char, filenames in kwfstats:
395 for char, filenames in kwfstats:
396 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
396 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
397 for f in filenames:
397 for f in filenames:
398 ui.write(fmt % repo.pathto(f, cwd))
398 ui.write(fmt % repo.pathto(f, cwd))
399
399
400 def shrink(ui, repo, *pats, **opts):
400 def shrink(ui, repo, *pats, **opts):
401 '''revert expanded keywords in the working directory
401 '''revert expanded keywords in the working directory
402
402
403 Run before changing/disabling active keywords or if you experience
403 Run before changing/disabling active keywords or if you experience
404 problems with "hg import" or "hg merge".
404 problems with "hg import" or "hg merge".
405
405
406 kwshrink refuses to run if given files contain local changes.
406 kwshrink refuses to run if given files contain local changes.
407 '''
407 '''
408 # 3rd argument sets expansion to False
408 # 3rd argument sets expansion to False
409 _kwfwrite(ui, repo, False, *pats, **opts)
409 _kwfwrite(ui, repo, False, *pats, **opts)
410
410
411
411
412 def uisetup(ui):
412 def uisetup(ui):
413 '''Collects [keyword] config in kwtools.
413 '''Collects [keyword] config in kwtools.
414 Monkeypatches dispatch._parse if needed.'''
414 Monkeypatches dispatch._parse if needed.'''
415
415
416 for pat, opt in ui.configitems('keyword'):
416 for pat, opt in ui.configitems('keyword'):
417 if opt != 'ignore':
417 if opt != 'ignore':
418 kwtools['inc'].append(pat)
418 kwtools['inc'].append(pat)
419 else:
419 else:
420 kwtools['exc'].append(pat)
420 kwtools['exc'].append(pat)
421
421
422 if kwtools['inc']:
422 if kwtools['inc']:
423 def kwdispatch_parse(orig, ui, args):
423 def kwdispatch_parse(orig, ui, args):
424 '''Monkeypatch dispatch._parse to obtain running hg command.'''
424 '''Monkeypatch dispatch._parse to obtain running hg command.'''
425 cmd, func, args, options, cmdoptions = orig(ui, args)
425 cmd, func, args, options, cmdoptions = orig(ui, args)
426 kwtools['hgcmd'] = cmd
426 kwtools['hgcmd'] = cmd
427 return cmd, func, args, options, cmdoptions
427 return cmd, func, args, options, cmdoptions
428
428
429 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
429 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
430
430
431 def reposetup(ui, repo):
431 def reposetup(ui, repo):
432 '''Sets up repo as kwrepo for keyword substitution.
432 '''Sets up repo as kwrepo for keyword substitution.
433 Overrides file method to return kwfilelog instead of filelog
433 Overrides file method to return kwfilelog instead of filelog
434 if file matches user configuration.
434 if file matches user configuration.
435 Wraps commit to overwrite configured files with updated
435 Wraps commit to overwrite configured files with updated
436 keyword substitutions.
436 keyword substitutions.
437 Monkeypatches patch and webcommands.'''
437 Monkeypatches patch and webcommands.'''
438
438
439 try:
439 try:
440 if (not repo.local() or not kwtools['inc']
440 if (not repo.local() or not kwtools['inc']
441 or kwtools['hgcmd'] in nokwcommands.split()
441 or kwtools['hgcmd'] in nokwcommands.split()
442 or '.hg' in util.splitpath(repo.root)
442 or '.hg' in util.splitpath(repo.root)
443 or repo._url.startswith('bundle:')):
443 or repo._url.startswith('bundle:')):
444 return
444 return
445 except AttributeError:
445 except AttributeError:
446 pass
446 pass
447
447
448 kwtools['templater'] = kwt = kwtemplater(ui, repo)
448 kwtools['templater'] = kwt = kwtemplater(ui, repo)
449
449
450 class kwrepo(repo.__class__):
450 class kwrepo(repo.__class__):
451 def file(self, f):
451 def file(self, f):
452 if f[0] == '/':
452 if f[0] == '/':
453 f = f[1:]
453 f = f[1:]
454 return kwfilelog(self.sopener, kwt, f)
454 return kwfilelog(self.sopener, kwt, f)
455
455
456 def wread(self, filename):
456 def wread(self, filename):
457 data = super(kwrepo, self).wread(filename)
457 data = super(kwrepo, self).wread(filename)
458 return kwt.wread(filename, data)
458 return kwt.wread(filename, data)
459
459
460 def commit(self, *args, **opts):
460 def commit(self, *args, **opts):
461 # use custom commitctx for user commands
461 # use custom commitctx for user commands
462 # other extensions can still wrap repo.commitctx directly
462 # other extensions can still wrap repo.commitctx directly
463 self.commitctx = self.kwcommitctx
463 self.commitctx = self.kwcommitctx
464 try:
464 try:
465 return super(kwrepo, self).commit(*args, **opts)
465 return super(kwrepo, self).commit(*args, **opts)
466 finally:
466 finally:
467 del self.commitctx
467 del self.commitctx
468
468
469 def kwcommitctx(self, ctx, error=False):
469 def kwcommitctx(self, ctx, error=False):
470 wlock = lock = None
470 wlock = lock = None
471 try:
471 try:
472 wlock = self.wlock()
472 wlock = self.wlock()
473 lock = self.lock()
473 lock = self.lock()
474 # store and postpone commit hooks
474 # store and postpone commit hooks
475 commithooks = {}
475 commithooks = {}
476 for name, cmd in ui.configitems('hooks'):
476 for name, cmd in ui.configitems('hooks'):
477 if name.split('.', 1)[0] == 'commit':
477 if name.split('.', 1)[0] == 'commit':
478 commithooks[name] = cmd
478 commithooks[name] = cmd
479 ui.setconfig('hooks', name, None)
479 ui.setconfig('hooks', name, None)
480 if commithooks:
480 if commithooks:
481 # store parents for commit hooks
481 # store parents for commit hooks
482 p1, p2 = ctx.p1(), ctx.p2()
482 p1, p2 = ctx.p1(), ctx.p2()
483 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
483 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
484
484
485 n = super(kwrepo, self).commitctx(ctx, error)
485 n = super(kwrepo, self).commitctx(ctx, error)
486
486
487 kwt.overwrite(n, True, None)
487 kwt.overwrite(n, True, None)
488 if commithooks:
488 if commithooks:
489 for name, cmd in commithooks.iteritems():
489 for name, cmd in commithooks.iteritems():
490 ui.setconfig('hooks', name, cmd)
490 ui.setconfig('hooks', name, cmd)
491 self.hook('commit', node=n, parent1=xp1, parent2=xp2)
491 self.hook('commit', node=n, parent1=xp1, parent2=xp2)
492 return n
492 return n
493 finally:
493 finally:
494 release(lock, wlock)
494 release(lock, wlock)
495
495
496 # monkeypatches
496 # monkeypatches
497 def kwpatchfile_init(orig, self, ui, fname, opener,
497 def kwpatchfile_init(orig, self, ui, fname, opener,
498 missing=False, eol=None):
498 missing=False, eol=None):
499 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
499 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
500 rejects or conflicts due to expanded keywords in working dir.'''
500 rejects or conflicts due to expanded keywords in working dir.'''
501 orig(self, ui, fname, opener, missing, eol)
501 orig(self, ui, fname, opener, missing, eol)
502 # shrink keywords read from working dir
502 # shrink keywords read from working dir
503 self.lines = kwt.shrinklines(self.fname, self.lines)
503 self.lines = kwt.shrinklines(self.fname, self.lines)
504
504
505 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
505 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
506 opts=None):
506 opts=None):
507 '''Monkeypatch patch.diff to avoid expansion except when
507 '''Monkeypatch patch.diff to avoid expansion except when
508 comparing against working dir.'''
508 comparing against working dir.'''
509 if node2 is not None:
509 if node2 is not None:
510 kwt.match = util.never
510 kwt.match = util.never
511 elif node1 is not None and node1 != repo['.'].node():
511 elif node1 is not None and node1 != repo['.'].node():
512 kwt.restrict = True
512 kwt.restrict = True
513 return orig(repo, node1, node2, match, changes, opts)
513 return orig(repo, node1, node2, match, changes, opts)
514
514
515 def kwweb_skip(orig, web, req, tmpl):
515 def kwweb_skip(orig, web, req, tmpl):
516 '''Wraps webcommands.x turning off keyword expansion.'''
516 '''Wraps webcommands.x turning off keyword expansion.'''
517 kwt.match = util.never
517 kwt.match = util.never
518 return orig(web, req, tmpl)
518 return orig(web, req, tmpl)
519
519
520 repo.__class__ = kwrepo
520 repo.__class__ = kwrepo
521
521
522 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
522 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
523 extensions.wrapfunction(patch, 'diff', kw_diff)
523 extensions.wrapfunction(patch, 'diff', kw_diff)
524 for c in 'annotate changeset rev filediff diff'.split():
524 for c in 'annotate changeset rev filediff diff'.split():
525 extensions.wrapfunction(webcommands, c, kwweb_skip)
525 extensions.wrapfunction(webcommands, c, kwweb_skip)
526
526
527 cmdtable = {
527 cmdtable = {
528 'kwdemo':
528 'kwdemo':
529 (demo,
529 (demo,
530 [('d', 'default', None, _('show default keyword template maps')),
530 [('d', 'default', None, _('show default keyword template maps')),
531 ('f', 'rcfile', [], _('read maps from rcfile'))],
531 ('f', 'rcfile', '', _('read maps from rcfile'))],
532 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
532 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
533 'kwexpand': (expand, commands.walkopts,
533 'kwexpand': (expand, commands.walkopts,
534 _('hg kwexpand [OPTION]... [FILE]...')),
534 _('hg kwexpand [OPTION]... [FILE]...')),
535 'kwfiles':
535 'kwfiles':
536 (files,
536 (files,
537 [('a', 'all', None, _('show keyword status flags of all files')),
537 [('a', 'all', None, _('show keyword status flags of all files')),
538 ('i', 'ignore', None, _('show files excluded from expansion')),
538 ('i', 'ignore', None, _('show files excluded from expansion')),
539 ('u', 'untracked', None, _('additionally show untracked files')),
539 ('u', 'untracked', None, _('additionally show untracked files')),
540 ] + commands.walkopts,
540 ] + commands.walkopts,
541 _('hg kwfiles [OPTION]... [FILE]...')),
541 _('hg kwfiles [OPTION]... [FILE]...')),
542 'kwshrink': (shrink, commands.walkopts,
542 'kwshrink': (shrink, commands.walkopts,
543 _('hg kwshrink [OPTION]... [FILE]...')),
543 _('hg kwshrink [OPTION]... [FILE]...')),
544 }
544 }
@@ -1,3518 +1,3520 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, subprocess, difflib, time, tempfile
11 import os, re, sys, subprocess, difflib, time, tempfile
12 import hg, util, revlog, bundlerepo, extensions, copies, context, error
12 import hg, util, revlog, bundlerepo, extensions, copies, context, error
13 import patch, help, mdiff, url, encoding
13 import patch, help, mdiff, url, encoding
14 import archival, changegroup, cmdutil, sshserver, hbisect
14 import archival, changegroup, cmdutil, sshserver, hbisect
15 from hgweb import server
15 from hgweb import server
16 import merge as merge_
16 import merge as merge_
17 import minirst
17 import minirst
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the repository.
24 Schedule files to be version controlled and added to the repository.
25
25
26 The files will be added to the repository at the next commit. To undo an
26 The files will be added to the repository at the next commit. To undo an
27 add before that, see hg forget.
27 add before that, see hg forget.
28
28
29 If no names are given, add all files to the repository.
29 If no names are given, add all files to the repository.
30 """
30 """
31
31
32 bad = []
32 bad = []
33 exacts = {}
33 exacts = {}
34 names = []
34 names = []
35 m = cmdutil.match(repo, pats, opts)
35 m = cmdutil.match(repo, pats, opts)
36 oldbad = m.bad
36 oldbad = m.bad
37 m.bad = lambda x,y: bad.append(x) or oldbad(x,y)
37 m.bad = lambda x,y: bad.append(x) or oldbad(x,y)
38
38
39 for f in repo.walk(m):
39 for f in repo.walk(m):
40 exact = m.exact(f)
40 exact = m.exact(f)
41 if exact or f not in repo.dirstate:
41 if exact or f not in repo.dirstate:
42 names.append(f)
42 names.append(f)
43 if ui.verbose or not exact:
43 if ui.verbose or not exact:
44 ui.status(_('adding %s\n') % m.rel(f))
44 ui.status(_('adding %s\n') % m.rel(f))
45 if not opts.get('dry_run'):
45 if not opts.get('dry_run'):
46 bad += [f for f in repo.add(names) if f in m.files()]
46 bad += [f for f in repo.add(names) if f in m.files()]
47 return bad and 1 or 0
47 return bad and 1 or 0
48
48
49 def addremove(ui, repo, *pats, **opts):
49 def addremove(ui, repo, *pats, **opts):
50 """add all new files, delete all missing files
50 """add all new files, delete all missing files
51
51
52 Add all new files and remove all missing files from the repository.
52 Add all new files and remove all missing files from the repository.
53
53
54 New files are ignored if they match any of the patterns in .hgignore. As
54 New files are ignored if they match any of the patterns in .hgignore. As
55 with add, these changes take effect at the next commit.
55 with add, these changes take effect at the next commit.
56
56
57 Use the -s/--similarity option to detect renamed files. With a parameter
57 Use the -s/--similarity option to detect renamed files. With a parameter
58 greater than 0, this compares every removed file with every added file and
58 greater than 0, this compares every removed file with every added file and
59 records those similar enough as renames. This option takes a percentage
59 records those similar enough as renames. This option takes a percentage
60 between 0 (disabled) and 100 (files must be identical) as its parameter.
60 between 0 (disabled) and 100 (files must be identical) as its parameter.
61 Detecting renamed files this way can be expensive.
61 Detecting renamed files this way can be expensive.
62 """
62 """
63 try:
63 try:
64 sim = float(opts.get('similarity') or 0)
64 sim = float(opts.get('similarity') or 0)
65 except ValueError:
65 except ValueError:
66 raise util.Abort(_('similarity must be a number'))
66 raise util.Abort(_('similarity must be a number'))
67 if sim < 0 or sim > 100:
67 if sim < 0 or sim > 100:
68 raise util.Abort(_('similarity must be between 0 and 100'))
68 raise util.Abort(_('similarity must be between 0 and 100'))
69 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
69 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
70
70
71 def annotate(ui, repo, *pats, **opts):
71 def annotate(ui, repo, *pats, **opts):
72 """show changeset information by line for each file
72 """show changeset information by line for each file
73
73
74 List changes in files, showing the revision id responsible for each line
74 List changes in files, showing the revision id responsible for each line
75
75
76 This command is useful for discovering when a change was made and by whom.
76 This command is useful for discovering when a change was made and by whom.
77
77
78 Without the -a/--text option, annotate will avoid processing files it
78 Without the -a/--text option, annotate will avoid processing files it
79 detects as binary. With -a, annotate will annotate the file anyway,
79 detects as binary. With -a, annotate will annotate the file anyway,
80 although the results will probably be neither useful nor desirable.
80 although the results will probably be neither useful nor desirable.
81 """
81 """
82 datefunc = ui.quiet and util.shortdate or util.datestr
82 datefunc = ui.quiet and util.shortdate or util.datestr
83 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
83 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
84
84
85 if not pats:
85 if not pats:
86 raise util.Abort(_('at least one filename or pattern is required'))
86 raise util.Abort(_('at least one filename or pattern is required'))
87
87
88 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
88 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
89 ('number', lambda x: str(x[0].rev())),
89 ('number', lambda x: str(x[0].rev())),
90 ('changeset', lambda x: short(x[0].node())),
90 ('changeset', lambda x: short(x[0].node())),
91 ('date', getdate),
91 ('date', getdate),
92 ('follow', lambda x: x[0].path()),
92 ('follow', lambda x: x[0].path()),
93 ]
93 ]
94
94
95 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
95 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
96 and not opts.get('follow')):
96 and not opts.get('follow')):
97 opts['number'] = 1
97 opts['number'] = 1
98
98
99 linenumber = opts.get('line_number') is not None
99 linenumber = opts.get('line_number') is not None
100 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
100 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
101 raise util.Abort(_('at least one of -n/-c is required for -l'))
101 raise util.Abort(_('at least one of -n/-c is required for -l'))
102
102
103 funcmap = [func for op, func in opmap if opts.get(op)]
103 funcmap = [func for op, func in opmap if opts.get(op)]
104 if linenumber:
104 if linenumber:
105 lastfunc = funcmap[-1]
105 lastfunc = funcmap[-1]
106 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
106 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
107
107
108 ctx = repo[opts.get('rev')]
108 ctx = repo[opts.get('rev')]
109
109
110 m = cmdutil.match(repo, pats, opts)
110 m = cmdutil.match(repo, pats, opts)
111 for abs in ctx.walk(m):
111 for abs in ctx.walk(m):
112 fctx = ctx[abs]
112 fctx = ctx[abs]
113 if not opts.get('text') and util.binary(fctx.data()):
113 if not opts.get('text') and util.binary(fctx.data()):
114 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
114 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
115 continue
115 continue
116
116
117 lines = fctx.annotate(follow=opts.get('follow'),
117 lines = fctx.annotate(follow=opts.get('follow'),
118 linenumber=linenumber)
118 linenumber=linenumber)
119 pieces = []
119 pieces = []
120
120
121 for f in funcmap:
121 for f in funcmap:
122 l = [f(n) for n, dummy in lines]
122 l = [f(n) for n, dummy in lines]
123 if l:
123 if l:
124 ml = max(map(len, l))
124 ml = max(map(len, l))
125 pieces.append(["%*s" % (ml, x) for x in l])
125 pieces.append(["%*s" % (ml, x) for x in l])
126
126
127 if pieces:
127 if pieces:
128 for p, l in zip(zip(*pieces), lines):
128 for p, l in zip(zip(*pieces), lines):
129 ui.write("%s: %s" % (" ".join(p), l[1]))
129 ui.write("%s: %s" % (" ".join(p), l[1]))
130
130
131 def archive(ui, repo, dest, **opts):
131 def archive(ui, repo, dest, **opts):
132 '''create an unversioned archive of a repository revision
132 '''create an unversioned archive of a repository revision
133
133
134 By default, the revision used is the parent of the working directory; use
134 By default, the revision used is the parent of the working directory; use
135 -r/--rev to specify a different revision.
135 -r/--rev to specify a different revision.
136
136
137 To specify the type of archive to create, use -t/--type. Valid types are::
137 To specify the type of archive to create, use -t/--type. Valid types are::
138
138
139 "files" (default): a directory full of files
139 "files" (default): a directory full of files
140 "tar": tar archive, uncompressed
140 "tar": tar archive, uncompressed
141 "tbz2": tar archive, compressed using bzip2
141 "tbz2": tar archive, compressed using bzip2
142 "tgz": tar archive, compressed using gzip
142 "tgz": tar archive, compressed using gzip
143 "uzip": zip archive, uncompressed
143 "uzip": zip archive, uncompressed
144 "zip": zip archive, compressed using deflate
144 "zip": zip archive, compressed using deflate
145
145
146 The exact name of the destination archive or directory is given using a
146 The exact name of the destination archive or directory is given using a
147 format string; see 'hg help export' for details.
147 format string; see 'hg help export' for details.
148
148
149 Each member added to an archive file has a directory prefix prepended. Use
149 Each member added to an archive file has a directory prefix prepended. Use
150 -p/--prefix to specify a format string for the prefix. The default is the
150 -p/--prefix to specify a format string for the prefix. The default is the
151 basename of the archive, with suffixes removed.
151 basename of the archive, with suffixes removed.
152 '''
152 '''
153
153
154 ctx = repo[opts.get('rev')]
154 ctx = repo[opts.get('rev')]
155 if not ctx:
155 if not ctx:
156 raise util.Abort(_('no working directory: please specify a revision'))
156 raise util.Abort(_('no working directory: please specify a revision'))
157 node = ctx.node()
157 node = ctx.node()
158 dest = cmdutil.make_filename(repo, dest, node)
158 dest = cmdutil.make_filename(repo, dest, node)
159 if os.path.realpath(dest) == repo.root:
159 if os.path.realpath(dest) == repo.root:
160 raise util.Abort(_('repository root cannot be destination'))
160 raise util.Abort(_('repository root cannot be destination'))
161 matchfn = cmdutil.match(repo, [], opts)
161 matchfn = cmdutil.match(repo, [], opts)
162 kind = opts.get('type') or 'files'
162 kind = opts.get('type') or 'files'
163 prefix = opts.get('prefix')
163 prefix = opts.get('prefix')
164 if dest == '-':
164 if dest == '-':
165 if kind == 'files':
165 if kind == 'files':
166 raise util.Abort(_('cannot archive plain files to stdout'))
166 raise util.Abort(_('cannot archive plain files to stdout'))
167 dest = sys.stdout
167 dest = sys.stdout
168 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
168 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
169 prefix = cmdutil.make_filename(repo, prefix, node)
169 prefix = cmdutil.make_filename(repo, prefix, node)
170 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
170 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
171 matchfn, prefix)
171 matchfn, prefix)
172
172
173 def backout(ui, repo, node=None, rev=None, **opts):
173 def backout(ui, repo, node=None, rev=None, **opts):
174 '''reverse effect of earlier changeset
174 '''reverse effect of earlier changeset
175
175
176 Commit the backed out changes as a new changeset. The new changeset is a
176 Commit the backed out changes as a new changeset. The new changeset is a
177 child of the backed out changeset.
177 child of the backed out changeset.
178
178
179 If you backout a changeset other than the tip, a new head is created. This
179 If you backout a changeset other than the tip, a new head is created. This
180 head will be the new tip and you should merge this backout changeset with
180 head will be the new tip and you should merge this backout changeset with
181 another head.
181 another head.
182
182
183 The --merge option remembers the parent of the working directory before
183 The --merge option remembers the parent of the working directory before
184 starting the backout, then merges the new head with that changeset
184 starting the backout, then merges the new head with that changeset
185 afterwards. This saves you from doing the merge by hand. The result of
185 afterwards. This saves you from doing the merge by hand. The result of
186 this merge is not committed, as with a normal merge.
186 this merge is not committed, as with a normal merge.
187
187
188 See 'hg help dates' for a list of formats valid for -d/--date.
188 See 'hg help dates' for a list of formats valid for -d/--date.
189 '''
189 '''
190 if rev and node:
190 if rev and node:
191 raise util.Abort(_("please specify just one revision"))
191 raise util.Abort(_("please specify just one revision"))
192
192
193 if not rev:
193 if not rev:
194 rev = node
194 rev = node
195
195
196 if not rev:
196 if not rev:
197 raise util.Abort(_("please specify a revision to backout"))
197 raise util.Abort(_("please specify a revision to backout"))
198
198
199 date = opts.get('date')
199 date = opts.get('date')
200 if date:
200 if date:
201 opts['date'] = util.parsedate(date)
201 opts['date'] = util.parsedate(date)
202
202
203 cmdutil.bail_if_changed(repo)
203 cmdutil.bail_if_changed(repo)
204 node = repo.lookup(rev)
204 node = repo.lookup(rev)
205
205
206 op1, op2 = repo.dirstate.parents()
206 op1, op2 = repo.dirstate.parents()
207 a = repo.changelog.ancestor(op1, node)
207 a = repo.changelog.ancestor(op1, node)
208 if a != node:
208 if a != node:
209 raise util.Abort(_('cannot backout change on a different branch'))
209 raise util.Abort(_('cannot backout change on a different branch'))
210
210
211 p1, p2 = repo.changelog.parents(node)
211 p1, p2 = repo.changelog.parents(node)
212 if p1 == nullid:
212 if p1 == nullid:
213 raise util.Abort(_('cannot backout a change with no parents'))
213 raise util.Abort(_('cannot backout a change with no parents'))
214 if p2 != nullid:
214 if p2 != nullid:
215 if not opts.get('parent'):
215 if not opts.get('parent'):
216 raise util.Abort(_('cannot backout a merge changeset without '
216 raise util.Abort(_('cannot backout a merge changeset without '
217 '--parent'))
217 '--parent'))
218 p = repo.lookup(opts['parent'])
218 p = repo.lookup(opts['parent'])
219 if p not in (p1, p2):
219 if p not in (p1, p2):
220 raise util.Abort(_('%s is not a parent of %s') %
220 raise util.Abort(_('%s is not a parent of %s') %
221 (short(p), short(node)))
221 (short(p), short(node)))
222 parent = p
222 parent = p
223 else:
223 else:
224 if opts.get('parent'):
224 if opts.get('parent'):
225 raise util.Abort(_('cannot use --parent on non-merge changeset'))
225 raise util.Abort(_('cannot use --parent on non-merge changeset'))
226 parent = p1
226 parent = p1
227
227
228 # the backout should appear on the same branch
228 # the backout should appear on the same branch
229 branch = repo.dirstate.branch()
229 branch = repo.dirstate.branch()
230 hg.clean(repo, node, show_stats=False)
230 hg.clean(repo, node, show_stats=False)
231 repo.dirstate.setbranch(branch)
231 repo.dirstate.setbranch(branch)
232 revert_opts = opts.copy()
232 revert_opts = opts.copy()
233 revert_opts['date'] = None
233 revert_opts['date'] = None
234 revert_opts['all'] = True
234 revert_opts['all'] = True
235 revert_opts['rev'] = hex(parent)
235 revert_opts['rev'] = hex(parent)
236 revert_opts['no_backup'] = None
236 revert_opts['no_backup'] = None
237 revert(ui, repo, **revert_opts)
237 revert(ui, repo, **revert_opts)
238 commit_opts = opts.copy()
238 commit_opts = opts.copy()
239 commit_opts['addremove'] = False
239 commit_opts['addremove'] = False
240 if not commit_opts['message'] and not commit_opts['logfile']:
240 if not commit_opts['message'] and not commit_opts['logfile']:
241 # we don't translate commit messages
241 # we don't translate commit messages
242 commit_opts['message'] = "Backed out changeset %s" % short(node)
242 commit_opts['message'] = "Backed out changeset %s" % short(node)
243 commit_opts['force_editor'] = True
243 commit_opts['force_editor'] = True
244 commit(ui, repo, **commit_opts)
244 commit(ui, repo, **commit_opts)
245 def nice(node):
245 def nice(node):
246 return '%d:%s' % (repo.changelog.rev(node), short(node))
246 return '%d:%s' % (repo.changelog.rev(node), short(node))
247 ui.status(_('changeset %s backs out changeset %s\n') %
247 ui.status(_('changeset %s backs out changeset %s\n') %
248 (nice(repo.changelog.tip()), nice(node)))
248 (nice(repo.changelog.tip()), nice(node)))
249 if op1 != node:
249 if op1 != node:
250 hg.clean(repo, op1, show_stats=False)
250 hg.clean(repo, op1, show_stats=False)
251 if opts.get('merge'):
251 if opts.get('merge'):
252 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
252 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
253 hg.merge(repo, hex(repo.changelog.tip()))
253 hg.merge(repo, hex(repo.changelog.tip()))
254 else:
254 else:
255 ui.status(_('the backout changeset is a new head - '
255 ui.status(_('the backout changeset is a new head - '
256 'do not forget to merge\n'))
256 'do not forget to merge\n'))
257 ui.status(_('(use "backout --merge" '
257 ui.status(_('(use "backout --merge" '
258 'if you want to auto-merge)\n'))
258 'if you want to auto-merge)\n'))
259
259
260 def bisect(ui, repo, rev=None, extra=None, command=None,
260 def bisect(ui, repo, rev=None, extra=None, command=None,
261 reset=None, good=None, bad=None, skip=None, noupdate=None):
261 reset=None, good=None, bad=None, skip=None, noupdate=None):
262 """subdivision search of changesets
262 """subdivision search of changesets
263
263
264 This command helps to find changesets which introduce problems. To use,
264 This command helps to find changesets which introduce problems. To use,
265 mark the earliest changeset you know exhibits the problem as bad, then
265 mark the earliest changeset you know exhibits the problem as bad, then
266 mark the latest changeset which is free from the problem as good. Bisect
266 mark the latest changeset which is free from the problem as good. Bisect
267 will update your working directory to a revision for testing (unless the
267 will update your working directory to a revision for testing (unless the
268 -U/--noupdate option is specified). Once you have performed tests, mark
268 -U/--noupdate option is specified). Once you have performed tests, mark
269 the working directory as good or bad, and bisect will either update to
269 the working directory as good or bad, and bisect will either update to
270 another candidate changeset or announce that it has found the bad
270 another candidate changeset or announce that it has found the bad
271 revision.
271 revision.
272
272
273 As a shortcut, you can also use the revision argument to mark a revision
273 As a shortcut, you can also use the revision argument to mark a revision
274 as good or bad without checking it out first.
274 as good or bad without checking it out first.
275
275
276 If you supply a command, it will be used for automatic bisection. Its exit
276 If you supply a command, it will be used for automatic bisection. Its exit
277 status will be used to mark revisions as good or bad: status 0 means good,
277 status will be used to mark revisions as good or bad: status 0 means good,
278 125 means to skip the revision, 127 (command not found) will abort the
278 125 means to skip the revision, 127 (command not found) will abort the
279 bisection, and any other non-zero exit status means the revision is bad.
279 bisection, and any other non-zero exit status means the revision is bad.
280 """
280 """
281 def print_result(nodes, good):
281 def print_result(nodes, good):
282 displayer = cmdutil.show_changeset(ui, repo, {})
282 displayer = cmdutil.show_changeset(ui, repo, {})
283 if len(nodes) == 1:
283 if len(nodes) == 1:
284 # narrowed it down to a single revision
284 # narrowed it down to a single revision
285 if good:
285 if good:
286 ui.write(_("The first good revision is:\n"))
286 ui.write(_("The first good revision is:\n"))
287 else:
287 else:
288 ui.write(_("The first bad revision is:\n"))
288 ui.write(_("The first bad revision is:\n"))
289 displayer.show(repo[nodes[0]])
289 displayer.show(repo[nodes[0]])
290 else:
290 else:
291 # multiple possible revisions
291 # multiple possible revisions
292 if good:
292 if good:
293 ui.write(_("Due to skipped revisions, the first "
293 ui.write(_("Due to skipped revisions, the first "
294 "good revision could be any of:\n"))
294 "good revision could be any of:\n"))
295 else:
295 else:
296 ui.write(_("Due to skipped revisions, the first "
296 ui.write(_("Due to skipped revisions, the first "
297 "bad revision could be any of:\n"))
297 "bad revision could be any of:\n"))
298 for n in nodes:
298 for n in nodes:
299 displayer.show(repo[n])
299 displayer.show(repo[n])
300
300
301 def check_state(state, interactive=True):
301 def check_state(state, interactive=True):
302 if not state['good'] or not state['bad']:
302 if not state['good'] or not state['bad']:
303 if (good or bad or skip or reset) and interactive:
303 if (good or bad or skip or reset) and interactive:
304 return
304 return
305 if not state['good']:
305 if not state['good']:
306 raise util.Abort(_('cannot bisect (no known good revisions)'))
306 raise util.Abort(_('cannot bisect (no known good revisions)'))
307 else:
307 else:
308 raise util.Abort(_('cannot bisect (no known bad revisions)'))
308 raise util.Abort(_('cannot bisect (no known bad revisions)'))
309 return True
309 return True
310
310
311 # backward compatibility
311 # backward compatibility
312 if rev in "good bad reset init".split():
312 if rev in "good bad reset init".split():
313 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
313 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
314 cmd, rev, extra = rev, extra, None
314 cmd, rev, extra = rev, extra, None
315 if cmd == "good":
315 if cmd == "good":
316 good = True
316 good = True
317 elif cmd == "bad":
317 elif cmd == "bad":
318 bad = True
318 bad = True
319 else:
319 else:
320 reset = True
320 reset = True
321 elif extra or good + bad + skip + reset + bool(command) > 1:
321 elif extra or good + bad + skip + reset + bool(command) > 1:
322 raise util.Abort(_('incompatible arguments'))
322 raise util.Abort(_('incompatible arguments'))
323
323
324 if reset:
324 if reset:
325 p = repo.join("bisect.state")
325 p = repo.join("bisect.state")
326 if os.path.exists(p):
326 if os.path.exists(p):
327 os.unlink(p)
327 os.unlink(p)
328 return
328 return
329
329
330 state = hbisect.load_state(repo)
330 state = hbisect.load_state(repo)
331
331
332 if command:
332 if command:
333 commandpath = util.find_exe(command)
333 commandpath = util.find_exe(command)
334 if commandpath is None:
334 if commandpath is None:
335 raise util.Abort(_("cannot find executable: %s") % command)
335 raise util.Abort(_("cannot find executable: %s") % command)
336 changesets = 1
336 changesets = 1
337 try:
337 try:
338 while changesets:
338 while changesets:
339 # update state
339 # update state
340 status = subprocess.call([commandpath])
340 status = subprocess.call([commandpath])
341 if status == 125:
341 if status == 125:
342 transition = "skip"
342 transition = "skip"
343 elif status == 0:
343 elif status == 0:
344 transition = "good"
344 transition = "good"
345 # status < 0 means process was killed
345 # status < 0 means process was killed
346 elif status == 127:
346 elif status == 127:
347 raise util.Abort(_("failed to execute %s") % command)
347 raise util.Abort(_("failed to execute %s") % command)
348 elif status < 0:
348 elif status < 0:
349 raise util.Abort(_("%s killed") % command)
349 raise util.Abort(_("%s killed") % command)
350 else:
350 else:
351 transition = "bad"
351 transition = "bad"
352 ctx = repo[rev or '.']
352 ctx = repo[rev or '.']
353 state[transition].append(ctx.node())
353 state[transition].append(ctx.node())
354 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
354 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
355 check_state(state, interactive=False)
355 check_state(state, interactive=False)
356 # bisect
356 # bisect
357 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
357 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
358 # update to next check
358 # update to next check
359 cmdutil.bail_if_changed(repo)
359 cmdutil.bail_if_changed(repo)
360 hg.clean(repo, nodes[0], show_stats=False)
360 hg.clean(repo, nodes[0], show_stats=False)
361 finally:
361 finally:
362 hbisect.save_state(repo, state)
362 hbisect.save_state(repo, state)
363 return print_result(nodes, not status)
363 return print_result(nodes, not status)
364
364
365 # update state
365 # update state
366 node = repo.lookup(rev or '.')
366 node = repo.lookup(rev or '.')
367 if good:
367 if good:
368 state['good'].append(node)
368 state['good'].append(node)
369 elif bad:
369 elif bad:
370 state['bad'].append(node)
370 state['bad'].append(node)
371 elif skip:
371 elif skip:
372 state['skip'].append(node)
372 state['skip'].append(node)
373
373
374 hbisect.save_state(repo, state)
374 hbisect.save_state(repo, state)
375
375
376 if not check_state(state):
376 if not check_state(state):
377 return
377 return
378
378
379 # actually bisect
379 # actually bisect
380 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
380 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
381 if changesets == 0:
381 if changesets == 0:
382 print_result(nodes, good)
382 print_result(nodes, good)
383 else:
383 else:
384 assert len(nodes) == 1 # only a single node can be tested next
384 assert len(nodes) == 1 # only a single node can be tested next
385 node = nodes[0]
385 node = nodes[0]
386 # compute the approximate number of remaining tests
386 # compute the approximate number of remaining tests
387 tests, size = 0, 2
387 tests, size = 0, 2
388 while size <= changesets:
388 while size <= changesets:
389 tests, size = tests + 1, size * 2
389 tests, size = tests + 1, size * 2
390 rev = repo.changelog.rev(node)
390 rev = repo.changelog.rev(node)
391 ui.write(_("Testing changeset %d:%s "
391 ui.write(_("Testing changeset %d:%s "
392 "(%d changesets remaining, ~%d tests)\n")
392 "(%d changesets remaining, ~%d tests)\n")
393 % (rev, short(node), changesets, tests))
393 % (rev, short(node), changesets, tests))
394 if not noupdate:
394 if not noupdate:
395 cmdutil.bail_if_changed(repo)
395 cmdutil.bail_if_changed(repo)
396 return hg.clean(repo, node)
396 return hg.clean(repo, node)
397
397
398 def branch(ui, repo, label=None, **opts):
398 def branch(ui, repo, label=None, **opts):
399 """set or show the current branch name
399 """set or show the current branch name
400
400
401 With no argument, show the current branch name. With one argument, set the
401 With no argument, show the current branch name. With one argument, set the
402 working directory branch name (the branch will not exist in the repository
402 working directory branch name (the branch will not exist in the repository
403 until the next commit). Standard practice recommends that primary
403 until the next commit). Standard practice recommends that primary
404 development take place on the 'default' branch.
404 development take place on the 'default' branch.
405
405
406 Unless -f/--force is specified, branch will not let you set a branch name
406 Unless -f/--force is specified, branch will not let you set a branch name
407 that already exists, even if it's inactive.
407 that already exists, even if it's inactive.
408
408
409 Use -C/--clean to reset the working directory branch to that of the parent
409 Use -C/--clean to reset the working directory branch to that of the parent
410 of the working directory, negating a previous branch change.
410 of the working directory, negating a previous branch change.
411
411
412 Use the command 'hg update' to switch to an existing branch. Use 'hg
412 Use the command 'hg update' to switch to an existing branch. Use 'hg
413 commit --close-branch' to mark this branch as closed.
413 commit --close-branch' to mark this branch as closed.
414 """
414 """
415
415
416 if opts.get('clean'):
416 if opts.get('clean'):
417 label = repo[None].parents()[0].branch()
417 label = repo[None].parents()[0].branch()
418 repo.dirstate.setbranch(label)
418 repo.dirstate.setbranch(label)
419 ui.status(_('reset working directory to branch %s\n') % label)
419 ui.status(_('reset working directory to branch %s\n') % label)
420 elif label:
420 elif label:
421 if not opts.get('force') and label in repo.branchtags():
421 if not opts.get('force') and label in repo.branchtags():
422 if label not in [p.branch() for p in repo.parents()]:
422 if label not in [p.branch() for p in repo.parents()]:
423 raise util.Abort(_('a branch of the same name already exists'
423 raise util.Abort(_('a branch of the same name already exists'
424 ' (use --force to override)'))
424 ' (use --force to override)'))
425 repo.dirstate.setbranch(encoding.fromlocal(label))
425 repo.dirstate.setbranch(encoding.fromlocal(label))
426 ui.status(_('marked working directory as branch %s\n') % label)
426 ui.status(_('marked working directory as branch %s\n') % label)
427 else:
427 else:
428 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
428 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
429
429
430 def branches(ui, repo, active=False, closed=False):
430 def branches(ui, repo, active=False, closed=False):
431 """list repository named branches
431 """list repository named branches
432
432
433 List the repository's named branches, indicating which ones are inactive.
433 List the repository's named branches, indicating which ones are inactive.
434 If -c/--closed is specified, also list branches which have been marked
434 If -c/--closed is specified, also list branches which have been marked
435 closed (see hg commit --close-branch).
435 closed (see hg commit --close-branch).
436
436
437 If -a/--active is specified, only show active branches. A branch is
437 If -a/--active is specified, only show active branches. A branch is
438 considered active if it contains repository heads.
438 considered active if it contains repository heads.
439
439
440 Use the command 'hg update' to switch to an existing branch.
440 Use the command 'hg update' to switch to an existing branch.
441 """
441 """
442
442
443 hexfunc = ui.debugflag and hex or short
443 hexfunc = ui.debugflag and hex or short
444 activebranches = [encoding.tolocal(repo[n].branch())
444 activebranches = [encoding.tolocal(repo[n].branch())
445 for n in repo.heads()]
445 for n in repo.heads()]
446 def testactive(tag, node):
446 def testactive(tag, node):
447 realhead = tag in activebranches
447 realhead = tag in activebranches
448 open = node in repo.branchheads(tag, closed=False)
448 open = node in repo.branchheads(tag, closed=False)
449 return realhead and open
449 return realhead and open
450 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
450 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
451 for tag, node in repo.branchtags().items()],
451 for tag, node in repo.branchtags().items()],
452 reverse=True)
452 reverse=True)
453
453
454 for isactive, node, tag in branches:
454 for isactive, node, tag in branches:
455 if (not active) or isactive:
455 if (not active) or isactive:
456 if ui.quiet:
456 if ui.quiet:
457 ui.write("%s\n" % tag)
457 ui.write("%s\n" % tag)
458 else:
458 else:
459 hn = repo.lookup(node)
459 hn = repo.lookup(node)
460 if isactive:
460 if isactive:
461 notice = ''
461 notice = ''
462 elif hn not in repo.branchheads(tag, closed=False):
462 elif hn not in repo.branchheads(tag, closed=False):
463 if not closed:
463 if not closed:
464 continue
464 continue
465 notice = ' (closed)'
465 notice = ' (closed)'
466 else:
466 else:
467 notice = ' (inactive)'
467 notice = ' (inactive)'
468 rev = str(node).rjust(31 - encoding.colwidth(tag))
468 rev = str(node).rjust(31 - encoding.colwidth(tag))
469 data = tag, rev, hexfunc(hn), notice
469 data = tag, rev, hexfunc(hn), notice
470 ui.write("%s %s:%s%s\n" % data)
470 ui.write("%s %s:%s%s\n" % data)
471
471
472 def bundle(ui, repo, fname, dest=None, **opts):
472 def bundle(ui, repo, fname, dest=None, **opts):
473 """create a changegroup file
473 """create a changegroup file
474
474
475 Generate a compressed changegroup file collecting changesets not known to
475 Generate a compressed changegroup file collecting changesets not known to
476 be in another repository.
476 be in another repository.
477
477
478 If no destination repository is specified the destination is assumed to
478 If no destination repository is specified the destination is assumed to
479 have all the nodes specified by one or more --base parameters. To create a
479 have all the nodes specified by one or more --base parameters. To create a
480 bundle containing all changesets, use -a/--all (or --base null).
480 bundle containing all changesets, use -a/--all (or --base null).
481
481
482 You can change compression method with the -t/--type option. The available
482 You can change compression method with the -t/--type option. The available
483 compression methods are: none, bzip2, and gzip (by default, bundles are
483 compression methods are: none, bzip2, and gzip (by default, bundles are
484 compressed using bzip2).
484 compressed using bzip2).
485
485
486 The bundle file can then be transferred using conventional means and
486 The bundle file can then be transferred using conventional means and
487 applied to another repository with the unbundle or pull command. This is
487 applied to another repository with the unbundle or pull command. This is
488 useful when direct push and pull are not available or when exporting an
488 useful when direct push and pull are not available or when exporting an
489 entire repository is undesirable.
489 entire repository is undesirable.
490
490
491 Applying bundles preserves all changeset contents including permissions,
491 Applying bundles preserves all changeset contents including permissions,
492 copy/rename information, and revision history.
492 copy/rename information, and revision history.
493 """
493 """
494 revs = opts.get('rev') or None
494 revs = opts.get('rev') or None
495 if revs:
495 if revs:
496 revs = [repo.lookup(rev) for rev in revs]
496 revs = [repo.lookup(rev) for rev in revs]
497 if opts.get('all'):
497 if opts.get('all'):
498 base = ['null']
498 base = ['null']
499 else:
499 else:
500 base = opts.get('base')
500 base = opts.get('base')
501 if base:
501 if base:
502 if dest:
502 if dest:
503 raise util.Abort(_("--base is incompatible with specifying "
503 raise util.Abort(_("--base is incompatible with specifying "
504 "a destination"))
504 "a destination"))
505 base = [repo.lookup(rev) for rev in base]
505 base = [repo.lookup(rev) for rev in base]
506 # create the right base
506 # create the right base
507 # XXX: nodesbetween / changegroup* should be "fixed" instead
507 # XXX: nodesbetween / changegroup* should be "fixed" instead
508 o = []
508 o = []
509 has = set((nullid,))
509 has = set((nullid,))
510 for n in base:
510 for n in base:
511 has.update(repo.changelog.reachable(n))
511 has.update(repo.changelog.reachable(n))
512 if revs:
512 if revs:
513 visit = list(revs)
513 visit = list(revs)
514 else:
514 else:
515 visit = repo.changelog.heads()
515 visit = repo.changelog.heads()
516 seen = {}
516 seen = {}
517 while visit:
517 while visit:
518 n = visit.pop(0)
518 n = visit.pop(0)
519 parents = [p for p in repo.changelog.parents(n) if p not in has]
519 parents = [p for p in repo.changelog.parents(n) if p not in has]
520 if len(parents) == 0:
520 if len(parents) == 0:
521 o.insert(0, n)
521 o.insert(0, n)
522 else:
522 else:
523 for p in parents:
523 for p in parents:
524 if p not in seen:
524 if p not in seen:
525 seen[p] = 1
525 seen[p] = 1
526 visit.append(p)
526 visit.append(p)
527 else:
527 else:
528 dest, revs, checkout = hg.parseurl(
528 dest, revs, checkout = hg.parseurl(
529 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
529 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
530 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
530 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
531 o = repo.findoutgoing(other, force=opts.get('force'))
531 o = repo.findoutgoing(other, force=opts.get('force'))
532
532
533 if revs:
533 if revs:
534 cg = repo.changegroupsubset(o, revs, 'bundle')
534 cg = repo.changegroupsubset(o, revs, 'bundle')
535 else:
535 else:
536 cg = repo.changegroup(o, 'bundle')
536 cg = repo.changegroup(o, 'bundle')
537
537
538 bundletype = opts.get('type', 'bzip2').lower()
538 bundletype = opts.get('type', 'bzip2').lower()
539 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
539 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
540 bundletype = btypes.get(bundletype)
540 bundletype = btypes.get(bundletype)
541 if bundletype not in changegroup.bundletypes:
541 if bundletype not in changegroup.bundletypes:
542 raise util.Abort(_('unknown bundle type specified with --type'))
542 raise util.Abort(_('unknown bundle type specified with --type'))
543
543
544 changegroup.writebundle(cg, fname, bundletype)
544 changegroup.writebundle(cg, fname, bundletype)
545
545
546 def cat(ui, repo, file1, *pats, **opts):
546 def cat(ui, repo, file1, *pats, **opts):
547 """output the current or given revision of files
547 """output the current or given revision of files
548
548
549 Print the specified files as they were at the given revision. If no
549 Print the specified files as they were at the given revision. If no
550 revision is given, the parent of the working directory is used, or tip if
550 revision is given, the parent of the working directory is used, or tip if
551 no revision is checked out.
551 no revision is checked out.
552
552
553 Output may be to a file, in which case the name of the file is given using
553 Output may be to a file, in which case the name of the file is given using
554 a format string. The formatting rules are the same as for the export
554 a format string. The formatting rules are the same as for the export
555 command, with the following additions::
555 command, with the following additions::
556
556
557 %s basename of file being printed
557 %s basename of file being printed
558 %d dirname of file being printed, or '.' if in repository root
558 %d dirname of file being printed, or '.' if in repository root
559 %p root-relative path name of file being printed
559 %p root-relative path name of file being printed
560 """
560 """
561 ctx = repo[opts.get('rev')]
561 ctx = repo[opts.get('rev')]
562 err = 1
562 err = 1
563 m = cmdutil.match(repo, (file1,) + pats, opts)
563 m = cmdutil.match(repo, (file1,) + pats, opts)
564 for abs in ctx.walk(m):
564 for abs in ctx.walk(m):
565 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
565 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
566 data = ctx[abs].data()
566 data = ctx[abs].data()
567 if opts.get('decode'):
567 if opts.get('decode'):
568 data = repo.wwritedata(abs, data)
568 data = repo.wwritedata(abs, data)
569 fp.write(data)
569 fp.write(data)
570 err = 0
570 err = 0
571 return err
571 return err
572
572
573 def clone(ui, source, dest=None, **opts):
573 def clone(ui, source, dest=None, **opts):
574 """make a copy of an existing repository
574 """make a copy of an existing repository
575
575
576 Create a copy of an existing repository in a new directory.
576 Create a copy of an existing repository in a new directory.
577
577
578 If no destination directory name is specified, it defaults to the basename
578 If no destination directory name is specified, it defaults to the basename
579 of the source.
579 of the source.
580
580
581 The location of the source is added to the new repository's .hg/hgrc file,
581 The location of the source is added to the new repository's .hg/hgrc file,
582 as the default to be used for future pulls.
582 as the default to be used for future pulls.
583
583
584 If you use the -r/--rev option to clone up to a specific revision, no
584 If you use the -r/--rev option to clone up to a specific revision, no
585 subsequent revisions (including subsequent tags) will be present in the
585 subsequent revisions (including subsequent tags) will be present in the
586 cloned repository. This option implies --pull, even on local repositories.
586 cloned repository. This option implies --pull, even on local repositories.
587
587
588 By default, clone will check out the head of the 'default' branch. If the
588 By default, clone will check out the head of the 'default' branch. If the
589 -U/--noupdate option is used, the new clone will contain only a repository
589 -U/--noupdate option is used, the new clone will contain only a repository
590 (.hg) and no working copy (the working copy parent is the null revision).
590 (.hg) and no working copy (the working copy parent is the null revision).
591
591
592 See 'hg help urls' for valid source format details.
592 See 'hg help urls' for valid source format details.
593
593
594 It is possible to specify an ssh:// URL as the destination, but no
594 It is possible to specify an ssh:// URL as the destination, but no
595 .hg/hgrc and working directory will be created on the remote side. Please
595 .hg/hgrc and working directory will be created on the remote side. Please
596 see 'hg help urls' for important details about ssh:// URLs.
596 see 'hg help urls' for important details about ssh:// URLs.
597
597
598 For efficiency, hardlinks are used for cloning whenever the source and
598 For efficiency, hardlinks are used for cloning whenever the source and
599 destination are on the same filesystem (note this applies only to the
599 destination are on the same filesystem (note this applies only to the
600 repository data, not to the checked out files). Some filesystems, such as
600 repository data, not to the checked out files). Some filesystems, such as
601 AFS, implement hardlinking incorrectly, but do not report errors. In these
601 AFS, implement hardlinking incorrectly, but do not report errors. In these
602 cases, use the --pull option to avoid hardlinking.
602 cases, use the --pull option to avoid hardlinking.
603
603
604 In some cases, you can clone repositories and checked out files using full
604 In some cases, you can clone repositories and checked out files using full
605 hardlinks with ::
605 hardlinks with ::
606
606
607 $ cp -al REPO REPOCLONE
607 $ cp -al REPO REPOCLONE
608
608
609 This is the fastest way to clone, but it is not always safe. The operation
609 This is the fastest way to clone, but it is not always safe. The operation
610 is not atomic (making sure REPO is not modified during the operation is up
610 is not atomic (making sure REPO is not modified during the operation is up
611 to you) and you have to make sure your editor breaks hardlinks (Emacs and
611 to you) and you have to make sure your editor breaks hardlinks (Emacs and
612 most Linux Kernel tools do so). Also, this is not compatible with certain
612 most Linux Kernel tools do so). Also, this is not compatible with certain
613 extensions that place their metadata under the .hg directory, such as mq.
613 extensions that place their metadata under the .hg directory, such as mq.
614 """
614 """
615 hg.clone(cmdutil.remoteui(ui, opts), source, dest,
615 hg.clone(cmdutil.remoteui(ui, opts), source, dest,
616 pull=opts.get('pull'),
616 pull=opts.get('pull'),
617 stream=opts.get('uncompressed'),
617 stream=opts.get('uncompressed'),
618 rev=opts.get('rev'),
618 rev=opts.get('rev'),
619 update=not opts.get('noupdate'))
619 update=not opts.get('noupdate'))
620
620
621 def commit(ui, repo, *pats, **opts):
621 def commit(ui, repo, *pats, **opts):
622 """commit the specified files or all outstanding changes
622 """commit the specified files or all outstanding changes
623
623
624 Commit changes to the given files into the repository. Unlike a
624 Commit changes to the given files into the repository. Unlike a
625 centralized RCS, this operation is a local operation. See hg push for a
625 centralized RCS, this operation is a local operation. See hg push for a
626 way to actively distribute your changes.
626 way to actively distribute your changes.
627
627
628 If a list of files is omitted, all changes reported by "hg status" will be
628 If a list of files is omitted, all changes reported by "hg status" will be
629 committed.
629 committed.
630
630
631 If you are committing the result of a merge, do not provide any filenames
631 If you are committing the result of a merge, do not provide any filenames
632 or -I/-X filters.
632 or -I/-X filters.
633
633
634 If no commit message is specified, the configured editor is started to
634 If no commit message is specified, the configured editor is started to
635 prompt you for a message.
635 prompt you for a message.
636
636
637 See 'hg help dates' for a list of formats valid for -d/--date.
637 See 'hg help dates' for a list of formats valid for -d/--date.
638 """
638 """
639 extra = {}
639 extra = {}
640 if opts.get('close_branch'):
640 if opts.get('close_branch'):
641 extra['close'] = 1
641 extra['close'] = 1
642 e = cmdutil.commiteditor
642 e = cmdutil.commiteditor
643 if opts.get('force_editor'):
643 if opts.get('force_editor'):
644 e = cmdutil.commitforceeditor
644 e = cmdutil.commitforceeditor
645
645
646 def commitfunc(ui, repo, message, match, opts):
646 def commitfunc(ui, repo, message, match, opts):
647 return repo.commit(message, opts.get('user'), opts.get('date'), match,
647 return repo.commit(message, opts.get('user'), opts.get('date'), match,
648 editor=e, extra=extra)
648 editor=e, extra=extra)
649
649
650 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
650 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
651 if not node:
651 if not node:
652 ui.status(_("nothing changed\n"))
652 ui.status(_("nothing changed\n"))
653 return
653 return
654 cl = repo.changelog
654 cl = repo.changelog
655 rev = cl.rev(node)
655 rev = cl.rev(node)
656 parents = cl.parentrevs(rev)
656 parents = cl.parentrevs(rev)
657 if rev - 1 in parents:
657 if rev - 1 in parents:
658 # one of the parents was the old tip
658 # one of the parents was the old tip
659 pass
659 pass
660 elif (parents == (nullrev, nullrev) or
660 elif (parents == (nullrev, nullrev) or
661 len(cl.heads(cl.node(parents[0]))) > 1 and
661 len(cl.heads(cl.node(parents[0]))) > 1 and
662 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
662 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
663 ui.status(_('created new head\n'))
663 ui.status(_('created new head\n'))
664
664
665 if ui.debugflag:
665 if ui.debugflag:
666 ui.write(_('committed changeset %d:%s\n') % (rev, hex(node)))
666 ui.write(_('committed changeset %d:%s\n') % (rev, hex(node)))
667 elif ui.verbose:
667 elif ui.verbose:
668 ui.write(_('committed changeset %d:%s\n') % (rev, short(node)))
668 ui.write(_('committed changeset %d:%s\n') % (rev, short(node)))
669
669
670 def copy(ui, repo, *pats, **opts):
670 def copy(ui, repo, *pats, **opts):
671 """mark files as copied for the next commit
671 """mark files as copied for the next commit
672
672
673 Mark dest as having copies of source files. If dest is a directory, copies
673 Mark dest as having copies of source files. If dest is a directory, copies
674 are put in that directory. If dest is a file, the source must be a single
674 are put in that directory. If dest is a file, the source must be a single
675 file.
675 file.
676
676
677 By default, this command copies the contents of files as they exist in the
677 By default, this command copies the contents of files as they exist in the
678 working directory. If invoked with -A/--after, the operation is recorded,
678 working directory. If invoked with -A/--after, the operation is recorded,
679 but no copying is performed.
679 but no copying is performed.
680
680
681 This command takes effect with the next commit. To undo a copy before
681 This command takes effect with the next commit. To undo a copy before
682 that, see hg revert.
682 that, see hg revert.
683 """
683 """
684 wlock = repo.wlock(False)
684 wlock = repo.wlock(False)
685 try:
685 try:
686 return cmdutil.copy(ui, repo, pats, opts)
686 return cmdutil.copy(ui, repo, pats, opts)
687 finally:
687 finally:
688 wlock.release()
688 wlock.release()
689
689
690 def debugancestor(ui, repo, *args):
690 def debugancestor(ui, repo, *args):
691 """find the ancestor revision of two revisions in a given index"""
691 """find the ancestor revision of two revisions in a given index"""
692 if len(args) == 3:
692 if len(args) == 3:
693 index, rev1, rev2 = args
693 index, rev1, rev2 = args
694 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
694 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
695 lookup = r.lookup
695 lookup = r.lookup
696 elif len(args) == 2:
696 elif len(args) == 2:
697 if not repo:
697 if not repo:
698 raise util.Abort(_("There is no Mercurial repository here "
698 raise util.Abort(_("There is no Mercurial repository here "
699 "(.hg not found)"))
699 "(.hg not found)"))
700 rev1, rev2 = args
700 rev1, rev2 = args
701 r = repo.changelog
701 r = repo.changelog
702 lookup = repo.lookup
702 lookup = repo.lookup
703 else:
703 else:
704 raise util.Abort(_('either two or three arguments required'))
704 raise util.Abort(_('either two or three arguments required'))
705 a = r.ancestor(lookup(rev1), lookup(rev2))
705 a = r.ancestor(lookup(rev1), lookup(rev2))
706 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
706 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
707
707
708 def debugcommands(ui, cmd='', *args):
708 def debugcommands(ui, cmd='', *args):
709 for cmd, vals in sorted(table.iteritems()):
709 for cmd, vals in sorted(table.iteritems()):
710 cmd = cmd.split('|')[0].strip('^')
710 cmd = cmd.split('|')[0].strip('^')
711 opts = ', '.join([i[1] for i in vals[1]])
711 opts = ', '.join([i[1] for i in vals[1]])
712 ui.write('%s: %s\n' % (cmd, opts))
712 ui.write('%s: %s\n' % (cmd, opts))
713
713
714 def debugcomplete(ui, cmd='', **opts):
714 def debugcomplete(ui, cmd='', **opts):
715 """returns the completion list associated with the given command"""
715 """returns the completion list associated with the given command"""
716
716
717 if opts.get('options'):
717 if opts.get('options'):
718 options = []
718 options = []
719 otables = [globalopts]
719 otables = [globalopts]
720 if cmd:
720 if cmd:
721 aliases, entry = cmdutil.findcmd(cmd, table, False)
721 aliases, entry = cmdutil.findcmd(cmd, table, False)
722 otables.append(entry[1])
722 otables.append(entry[1])
723 for t in otables:
723 for t in otables:
724 for o in t:
724 for o in t:
725 if o[0]:
725 if o[0]:
726 options.append('-%s' % o[0])
726 options.append('-%s' % o[0])
727 options.append('--%s' % o[1])
727 options.append('--%s' % o[1])
728 ui.write("%s\n" % "\n".join(options))
728 ui.write("%s\n" % "\n".join(options))
729 return
729 return
730
730
731 cmdlist = cmdutil.findpossible(cmd, table)
731 cmdlist = cmdutil.findpossible(cmd, table)
732 if ui.verbose:
732 if ui.verbose:
733 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
733 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
734 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
734 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
735
735
736 def debugfsinfo(ui, path = "."):
736 def debugfsinfo(ui, path = "."):
737 open('.debugfsinfo', 'w').write('')
737 open('.debugfsinfo', 'w').write('')
738 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
738 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
739 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
739 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
740 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
740 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
741 and 'yes' or 'no'))
741 and 'yes' or 'no'))
742 os.unlink('.debugfsinfo')
742 os.unlink('.debugfsinfo')
743
743
744 def debugrebuildstate(ui, repo, rev="tip"):
744 def debugrebuildstate(ui, repo, rev="tip"):
745 """rebuild the dirstate as it would look like for the given revision"""
745 """rebuild the dirstate as it would look like for the given revision"""
746 ctx = repo[rev]
746 ctx = repo[rev]
747 wlock = repo.wlock()
747 wlock = repo.wlock()
748 try:
748 try:
749 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
749 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
750 finally:
750 finally:
751 wlock.release()
751 wlock.release()
752
752
753 def debugcheckstate(ui, repo):
753 def debugcheckstate(ui, repo):
754 """validate the correctness of the current dirstate"""
754 """validate the correctness of the current dirstate"""
755 parent1, parent2 = repo.dirstate.parents()
755 parent1, parent2 = repo.dirstate.parents()
756 m1 = repo[parent1].manifest()
756 m1 = repo[parent1].manifest()
757 m2 = repo[parent2].manifest()
757 m2 = repo[parent2].manifest()
758 errors = 0
758 errors = 0
759 for f in repo.dirstate:
759 for f in repo.dirstate:
760 state = repo.dirstate[f]
760 state = repo.dirstate[f]
761 if state in "nr" and f not in m1:
761 if state in "nr" and f not in m1:
762 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
762 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
763 errors += 1
763 errors += 1
764 if state in "a" and f in m1:
764 if state in "a" and f in m1:
765 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
765 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
766 errors += 1
766 errors += 1
767 if state in "m" and f not in m1 and f not in m2:
767 if state in "m" and f not in m1 and f not in m2:
768 ui.warn(_("%s in state %s, but not in either manifest\n") %
768 ui.warn(_("%s in state %s, but not in either manifest\n") %
769 (f, state))
769 (f, state))
770 errors += 1
770 errors += 1
771 for f in m1:
771 for f in m1:
772 state = repo.dirstate[f]
772 state = repo.dirstate[f]
773 if state not in "nrm":
773 if state not in "nrm":
774 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
774 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
775 errors += 1
775 errors += 1
776 if errors:
776 if errors:
777 error = _(".hg/dirstate inconsistent with current parent's manifest")
777 error = _(".hg/dirstate inconsistent with current parent's manifest")
778 raise util.Abort(error)
778 raise util.Abort(error)
779
779
780 def showconfig(ui, repo, *values, **opts):
780 def showconfig(ui, repo, *values, **opts):
781 """show combined config settings from all hgrc files
781 """show combined config settings from all hgrc files
782
782
783 With no arguments, print names and values of all config items.
783 With no arguments, print names and values of all config items.
784
784
785 With one argument of the form section.name, print just the value of that
785 With one argument of the form section.name, print just the value of that
786 config item.
786 config item.
787
787
788 With multiple arguments, print names and values of all config items with
788 With multiple arguments, print names and values of all config items with
789 matching section names.
789 matching section names.
790
790
791 With --debug, the source (filename and line number) is printed for each
791 With --debug, the source (filename and line number) is printed for each
792 config item.
792 config item.
793 """
793 """
794
794
795 untrusted = bool(opts.get('untrusted'))
795 untrusted = bool(opts.get('untrusted'))
796 if values:
796 if values:
797 if len([v for v in values if '.' in v]) > 1:
797 if len([v for v in values if '.' in v]) > 1:
798 raise util.Abort(_('only one config item permitted'))
798 raise util.Abort(_('only one config item permitted'))
799 for section, name, value in ui.walkconfig(untrusted=untrusted):
799 for section, name, value in ui.walkconfig(untrusted=untrusted):
800 sectname = section + '.' + name
800 sectname = section + '.' + name
801 if values:
801 if values:
802 for v in values:
802 for v in values:
803 if v == section:
803 if v == section:
804 ui.debug('%s: ' %
804 ui.debug('%s: ' %
805 ui.configsource(section, name, untrusted))
805 ui.configsource(section, name, untrusted))
806 ui.write('%s=%s\n' % (sectname, value))
806 ui.write('%s=%s\n' % (sectname, value))
807 elif v == sectname:
807 elif v == sectname:
808 ui.debug('%s: ' %
808 ui.debug('%s: ' %
809 ui.configsource(section, name, untrusted))
809 ui.configsource(section, name, untrusted))
810 ui.write(value, '\n')
810 ui.write(value, '\n')
811 else:
811 else:
812 ui.debug('%s: ' %
812 ui.debug('%s: ' %
813 ui.configsource(section, name, untrusted))
813 ui.configsource(section, name, untrusted))
814 ui.write('%s=%s\n' % (sectname, value))
814 ui.write('%s=%s\n' % (sectname, value))
815
815
816 def debugsetparents(ui, repo, rev1, rev2=None):
816 def debugsetparents(ui, repo, rev1, rev2=None):
817 """manually set the parents of the current working directory
817 """manually set the parents of the current working directory
818
818
819 This is useful for writing repository conversion tools, but should be used
819 This is useful for writing repository conversion tools, but should be used
820 with care.
820 with care.
821 """
821 """
822
822
823 if not rev2:
823 if not rev2:
824 rev2 = hex(nullid)
824 rev2 = hex(nullid)
825
825
826 wlock = repo.wlock()
826 wlock = repo.wlock()
827 try:
827 try:
828 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
828 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
829 finally:
829 finally:
830 wlock.release()
830 wlock.release()
831
831
832 def debugstate(ui, repo, nodates=None):
832 def debugstate(ui, repo, nodates=None):
833 """show the contents of the current dirstate"""
833 """show the contents of the current dirstate"""
834 timestr = ""
834 timestr = ""
835 showdate = not nodates
835 showdate = not nodates
836 for file_, ent in sorted(repo.dirstate._map.iteritems()):
836 for file_, ent in sorted(repo.dirstate._map.iteritems()):
837 if showdate:
837 if showdate:
838 if ent[3] == -1:
838 if ent[3] == -1:
839 # Pad or slice to locale representation
839 # Pad or slice to locale representation
840 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
840 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
841 timestr = 'unset'
841 timestr = 'unset'
842 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
842 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
843 else:
843 else:
844 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
844 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
845 if ent[1] & 020000:
845 if ent[1] & 020000:
846 mode = 'lnk'
846 mode = 'lnk'
847 else:
847 else:
848 mode = '%3o' % (ent[1] & 0777)
848 mode = '%3o' % (ent[1] & 0777)
849 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
849 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
850 for f in repo.dirstate.copies():
850 for f in repo.dirstate.copies():
851 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
851 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
852
852
853 def debugsub(ui, repo, rev=None):
853 def debugsub(ui, repo, rev=None):
854 if rev == '':
854 if rev == '':
855 rev = None
855 rev = None
856 for k,v in sorted(repo[rev].substate.items()):
856 for k,v in sorted(repo[rev].substate.items()):
857 ui.write('path %s\n' % k)
857 ui.write('path %s\n' % k)
858 ui.write(' source %s\n' % v[0])
858 ui.write(' source %s\n' % v[0])
859 ui.write(' revision %s\n' % v[1])
859 ui.write(' revision %s\n' % v[1])
860
860
861 def debugdata(ui, file_, rev):
861 def debugdata(ui, file_, rev):
862 """dump the contents of a data file revision"""
862 """dump the contents of a data file revision"""
863 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
863 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
864 try:
864 try:
865 ui.write(r.revision(r.lookup(rev)))
865 ui.write(r.revision(r.lookup(rev)))
866 except KeyError:
866 except KeyError:
867 raise util.Abort(_('invalid revision identifier %s') % rev)
867 raise util.Abort(_('invalid revision identifier %s') % rev)
868
868
869 def debugdate(ui, date, range=None, **opts):
869 def debugdate(ui, date, range=None, **opts):
870 """parse and display a date"""
870 """parse and display a date"""
871 if opts["extended"]:
871 if opts["extended"]:
872 d = util.parsedate(date, util.extendeddateformats)
872 d = util.parsedate(date, util.extendeddateformats)
873 else:
873 else:
874 d = util.parsedate(date)
874 d = util.parsedate(date)
875 ui.write("internal: %s %s\n" % d)
875 ui.write("internal: %s %s\n" % d)
876 ui.write("standard: %s\n" % util.datestr(d))
876 ui.write("standard: %s\n" % util.datestr(d))
877 if range:
877 if range:
878 m = util.matchdate(range)
878 m = util.matchdate(range)
879 ui.write("match: %s\n" % m(d[0]))
879 ui.write("match: %s\n" % m(d[0]))
880
880
881 def debugindex(ui, file_):
881 def debugindex(ui, file_):
882 """dump the contents of an index file"""
882 """dump the contents of an index file"""
883 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
883 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
884 ui.write(" rev offset length base linkrev"
884 ui.write(" rev offset length base linkrev"
885 " nodeid p1 p2\n")
885 " nodeid p1 p2\n")
886 for i in r:
886 for i in r:
887 node = r.node(i)
887 node = r.node(i)
888 try:
888 try:
889 pp = r.parents(node)
889 pp = r.parents(node)
890 except:
890 except:
891 pp = [nullid, nullid]
891 pp = [nullid, nullid]
892 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
892 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
893 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
893 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
894 short(node), short(pp[0]), short(pp[1])))
894 short(node), short(pp[0]), short(pp[1])))
895
895
896 def debugindexdot(ui, file_):
896 def debugindexdot(ui, file_):
897 """dump an index DAG as a graphviz dot file"""
897 """dump an index DAG as a graphviz dot file"""
898 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
898 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
899 ui.write("digraph G {\n")
899 ui.write("digraph G {\n")
900 for i in r:
900 for i in r:
901 node = r.node(i)
901 node = r.node(i)
902 pp = r.parents(node)
902 pp = r.parents(node)
903 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
903 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
904 if pp[1] != nullid:
904 if pp[1] != nullid:
905 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
905 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
906 ui.write("}\n")
906 ui.write("}\n")
907
907
908 def debuginstall(ui):
908 def debuginstall(ui):
909 '''test Mercurial installation'''
909 '''test Mercurial installation'''
910
910
911 def writetemp(contents):
911 def writetemp(contents):
912 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
912 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
913 f = os.fdopen(fd, "wb")
913 f = os.fdopen(fd, "wb")
914 f.write(contents)
914 f.write(contents)
915 f.close()
915 f.close()
916 return name
916 return name
917
917
918 problems = 0
918 problems = 0
919
919
920 # encoding
920 # encoding
921 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
921 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
922 try:
922 try:
923 encoding.fromlocal("test")
923 encoding.fromlocal("test")
924 except util.Abort, inst:
924 except util.Abort, inst:
925 ui.write(" %s\n" % inst)
925 ui.write(" %s\n" % inst)
926 ui.write(_(" (check that your locale is properly set)\n"))
926 ui.write(_(" (check that your locale is properly set)\n"))
927 problems += 1
927 problems += 1
928
928
929 # compiled modules
929 # compiled modules
930 ui.status(_("Checking extensions...\n"))
930 ui.status(_("Checking extensions...\n"))
931 try:
931 try:
932 import bdiff, mpatch, base85
932 import bdiff, mpatch, base85
933 except Exception, inst:
933 except Exception, inst:
934 ui.write(" %s\n" % inst)
934 ui.write(" %s\n" % inst)
935 ui.write(_(" One or more extensions could not be found"))
935 ui.write(_(" One or more extensions could not be found"))
936 ui.write(_(" (check that you compiled the extensions)\n"))
936 ui.write(_(" (check that you compiled the extensions)\n"))
937 problems += 1
937 problems += 1
938
938
939 # templates
939 # templates
940 ui.status(_("Checking templates...\n"))
940 ui.status(_("Checking templates...\n"))
941 try:
941 try:
942 import templater
942 import templater
943 templater.templater(templater.templatepath("map-cmdline.default"))
943 templater.templater(templater.templatepath("map-cmdline.default"))
944 except Exception, inst:
944 except Exception, inst:
945 ui.write(" %s\n" % inst)
945 ui.write(" %s\n" % inst)
946 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
946 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
947 problems += 1
947 problems += 1
948
948
949 # patch
949 # patch
950 ui.status(_("Checking patch...\n"))
950 ui.status(_("Checking patch...\n"))
951 patchproblems = 0
951 patchproblems = 0
952 a = "1\n2\n3\n4\n"
952 a = "1\n2\n3\n4\n"
953 b = "1\n2\n3\ninsert\n4\n"
953 b = "1\n2\n3\ninsert\n4\n"
954 fa = writetemp(a)
954 fa = writetemp(a)
955 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
955 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
956 os.path.basename(fa))
956 os.path.basename(fa))
957 fd = writetemp(d)
957 fd = writetemp(d)
958
958
959 files = {}
959 files = {}
960 try:
960 try:
961 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
961 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
962 except util.Abort, e:
962 except util.Abort, e:
963 ui.write(_(" patch call failed:\n"))
963 ui.write(_(" patch call failed:\n"))
964 ui.write(" " + str(e) + "\n")
964 ui.write(" " + str(e) + "\n")
965 patchproblems += 1
965 patchproblems += 1
966 else:
966 else:
967 if list(files) != [os.path.basename(fa)]:
967 if list(files) != [os.path.basename(fa)]:
968 ui.write(_(" unexpected patch output!\n"))
968 ui.write(_(" unexpected patch output!\n"))
969 patchproblems += 1
969 patchproblems += 1
970 a = open(fa).read()
970 a = open(fa).read()
971 if a != b:
971 if a != b:
972 ui.write(_(" patch test failed!\n"))
972 ui.write(_(" patch test failed!\n"))
973 patchproblems += 1
973 patchproblems += 1
974
974
975 if patchproblems:
975 if patchproblems:
976 if ui.config('ui', 'patch'):
976 if ui.config('ui', 'patch'):
977 ui.write(_(" (Current patch tool may be incompatible with patch,"
977 ui.write(_(" (Current patch tool may be incompatible with patch,"
978 " or misconfigured. Please check your .hgrc file)\n"))
978 " or misconfigured. Please check your .hgrc file)\n"))
979 else:
979 else:
980 ui.write(_(" Internal patcher failure, please report this error"
980 ui.write(_(" Internal patcher failure, please report this error"
981 " to http://mercurial.selenic.com/bts/\n"))
981 " to http://mercurial.selenic.com/bts/\n"))
982 problems += patchproblems
982 problems += patchproblems
983
983
984 os.unlink(fa)
984 os.unlink(fa)
985 os.unlink(fd)
985 os.unlink(fd)
986
986
987 # editor
987 # editor
988 ui.status(_("Checking commit editor...\n"))
988 ui.status(_("Checking commit editor...\n"))
989 editor = ui.geteditor()
989 editor = ui.geteditor()
990 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
990 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
991 if not cmdpath:
991 if not cmdpath:
992 if editor == 'vi':
992 if editor == 'vi':
993 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
993 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
994 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
994 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
995 else:
995 else:
996 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
996 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
997 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
997 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
998 problems += 1
998 problems += 1
999
999
1000 # check username
1000 # check username
1001 ui.status(_("Checking username...\n"))
1001 ui.status(_("Checking username...\n"))
1002 user = os.environ.get("HGUSER")
1002 user = os.environ.get("HGUSER")
1003 if user is None:
1003 if user is None:
1004 user = ui.config("ui", "username")
1004 user = ui.config("ui", "username")
1005 if user is None:
1005 if user is None:
1006 user = os.environ.get("EMAIL")
1006 user = os.environ.get("EMAIL")
1007 if not user:
1007 if not user:
1008 ui.warn(" ")
1008 ui.warn(" ")
1009 ui.username()
1009 ui.username()
1010 ui.write(_(" (specify a username in your .hgrc file)\n"))
1010 ui.write(_(" (specify a username in your .hgrc file)\n"))
1011
1011
1012 if not problems:
1012 if not problems:
1013 ui.status(_("No problems detected\n"))
1013 ui.status(_("No problems detected\n"))
1014 else:
1014 else:
1015 ui.write(_("%s problems detected,"
1015 ui.write(_("%s problems detected,"
1016 " please check your install!\n") % problems)
1016 " please check your install!\n") % problems)
1017
1017
1018 return problems
1018 return problems
1019
1019
1020 def debugrename(ui, repo, file1, *pats, **opts):
1020 def debugrename(ui, repo, file1, *pats, **opts):
1021 """dump rename information"""
1021 """dump rename information"""
1022
1022
1023 ctx = repo[opts.get('rev')]
1023 ctx = repo[opts.get('rev')]
1024 m = cmdutil.match(repo, (file1,) + pats, opts)
1024 m = cmdutil.match(repo, (file1,) + pats, opts)
1025 for abs in ctx.walk(m):
1025 for abs in ctx.walk(m):
1026 fctx = ctx[abs]
1026 fctx = ctx[abs]
1027 o = fctx.filelog().renamed(fctx.filenode())
1027 o = fctx.filelog().renamed(fctx.filenode())
1028 rel = m.rel(abs)
1028 rel = m.rel(abs)
1029 if o:
1029 if o:
1030 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1030 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1031 else:
1031 else:
1032 ui.write(_("%s not renamed\n") % rel)
1032 ui.write(_("%s not renamed\n") % rel)
1033
1033
1034 def debugwalk(ui, repo, *pats, **opts):
1034 def debugwalk(ui, repo, *pats, **opts):
1035 """show how files match on given patterns"""
1035 """show how files match on given patterns"""
1036 m = cmdutil.match(repo, pats, opts)
1036 m = cmdutil.match(repo, pats, opts)
1037 items = list(repo.walk(m))
1037 items = list(repo.walk(m))
1038 if not items:
1038 if not items:
1039 return
1039 return
1040 fmt = 'f %%-%ds %%-%ds %%s' % (
1040 fmt = 'f %%-%ds %%-%ds %%s' % (
1041 max([len(abs) for abs in items]),
1041 max([len(abs) for abs in items]),
1042 max([len(m.rel(abs)) for abs in items]))
1042 max([len(m.rel(abs)) for abs in items]))
1043 for abs in items:
1043 for abs in items:
1044 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1044 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1045 ui.write("%s\n" % line.rstrip())
1045 ui.write("%s\n" % line.rstrip())
1046
1046
1047 def diff(ui, repo, *pats, **opts):
1047 def diff(ui, repo, *pats, **opts):
1048 """diff repository (or selected files)
1048 """diff repository (or selected files)
1049
1049
1050 Show differences between revisions for the specified files.
1050 Show differences between revisions for the specified files.
1051
1051
1052 Differences between files are shown using the unified diff format.
1052 Differences between files are shown using the unified diff format.
1053
1053
1054 NOTE: diff may generate unexpected results for merges, as it will default
1054 NOTE: diff may generate unexpected results for merges, as it will default
1055 to comparing against the working directory's first parent changeset if no
1055 to comparing against the working directory's first parent changeset if no
1056 revisions are specified.
1056 revisions are specified.
1057
1057
1058 When two revision arguments are given, then changes are shown between
1058 When two revision arguments are given, then changes are shown between
1059 those revisions. If only one revision is specified then that revision is
1059 those revisions. If only one revision is specified then that revision is
1060 compared to the working directory, and, when no revisions are specified,
1060 compared to the working directory, and, when no revisions are specified,
1061 the working directory files are compared to its parent.
1061 the working directory files are compared to its parent.
1062
1062
1063 Without the -a/--text option, diff will avoid generating diffs of files it
1063 Without the -a/--text option, diff will avoid generating diffs of files it
1064 detects as binary. With -a, diff will generate a diff anyway, probably
1064 detects as binary. With -a, diff will generate a diff anyway, probably
1065 with undesirable results.
1065 with undesirable results.
1066
1066
1067 Use the -g/--git option to generate diffs in the git extended diff format.
1067 Use the -g/--git option to generate diffs in the git extended diff format.
1068 For more information, read 'hg help diffs'.
1068 For more information, read 'hg help diffs'.
1069 """
1069 """
1070
1070
1071 revs = opts.get('rev')
1071 revs = opts.get('rev')
1072 change = opts.get('change')
1072 change = opts.get('change')
1073
1073
1074 if revs and change:
1074 if revs and change:
1075 msg = _('cannot specify --rev and --change at the same time')
1075 msg = _('cannot specify --rev and --change at the same time')
1076 raise util.Abort(msg)
1076 raise util.Abort(msg)
1077 elif change:
1077 elif change:
1078 node2 = repo.lookup(change)
1078 node2 = repo.lookup(change)
1079 node1 = repo[node2].parents()[0].node()
1079 node1 = repo[node2].parents()[0].node()
1080 else:
1080 else:
1081 node1, node2 = cmdutil.revpair(repo, revs)
1081 node1, node2 = cmdutil.revpair(repo, revs)
1082
1082
1083 m = cmdutil.match(repo, pats, opts)
1083 m = cmdutil.match(repo, pats, opts)
1084 it = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1084 it = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1085 for chunk in it:
1085 for chunk in it:
1086 ui.write(chunk)
1086 ui.write(chunk)
1087
1087
1088 def export(ui, repo, *changesets, **opts):
1088 def export(ui, repo, *changesets, **opts):
1089 """dump the header and diffs for one or more changesets
1089 """dump the header and diffs for one or more changesets
1090
1090
1091 Print the changeset header and diffs for one or more revisions.
1091 Print the changeset header and diffs for one or more revisions.
1092
1092
1093 The information shown in the changeset header is: author, changeset hash,
1093 The information shown in the changeset header is: author, changeset hash,
1094 parent(s) and commit comment.
1094 parent(s) and commit comment.
1095
1095
1096 NOTE: export may generate unexpected diff output for merge changesets, as
1096 NOTE: export may generate unexpected diff output for merge changesets, as
1097 it will compare the merge changeset against its first parent only.
1097 it will compare the merge changeset against its first parent only.
1098
1098
1099 Output may be to a file, in which case the name of the file is given using
1099 Output may be to a file, in which case the name of the file is given using
1100 a format string. The formatting rules are as follows::
1100 a format string. The formatting rules are as follows::
1101
1101
1102 %% literal "%" character
1102 %% literal "%" character
1103 %H changeset hash (40 bytes of hexadecimal)
1103 %H changeset hash (40 bytes of hexadecimal)
1104 %N number of patches being generated
1104 %N number of patches being generated
1105 %R changeset revision number
1105 %R changeset revision number
1106 %b basename of the exporting repository
1106 %b basename of the exporting repository
1107 %h short-form changeset hash (12 bytes of hexadecimal)
1107 %h short-form changeset hash (12 bytes of hexadecimal)
1108 %n zero-padded sequence number, starting at 1
1108 %n zero-padded sequence number, starting at 1
1109 %r zero-padded changeset revision number
1109 %r zero-padded changeset revision number
1110
1110
1111 Without the -a/--text option, export will avoid generating diffs of files
1111 Without the -a/--text option, export will avoid generating diffs of files
1112 it detects as binary. With -a, export will generate a diff anyway,
1112 it detects as binary. With -a, export will generate a diff anyway,
1113 probably with undesirable results.
1113 probably with undesirable results.
1114
1114
1115 Use the -g/--git option to generate diffs in the git extended diff format.
1115 Use the -g/--git option to generate diffs in the git extended diff format.
1116 See 'hg help diffs' for more information.
1116 See 'hg help diffs' for more information.
1117
1117
1118 With the --switch-parent option, the diff will be against the second
1118 With the --switch-parent option, the diff will be against the second
1119 parent. It can be useful to review a merge.
1119 parent. It can be useful to review a merge.
1120 """
1120 """
1121 if not changesets:
1121 if not changesets:
1122 raise util.Abort(_("export requires at least one changeset"))
1122 raise util.Abort(_("export requires at least one changeset"))
1123 revs = cmdutil.revrange(repo, changesets)
1123 revs = cmdutil.revrange(repo, changesets)
1124 if len(revs) > 1:
1124 if len(revs) > 1:
1125 ui.note(_('exporting patches:\n'))
1125 ui.note(_('exporting patches:\n'))
1126 else:
1126 else:
1127 ui.note(_('exporting patch:\n'))
1127 ui.note(_('exporting patch:\n'))
1128 patch.export(repo, revs, template=opts.get('output'),
1128 patch.export(repo, revs, template=opts.get('output'),
1129 switch_parent=opts.get('switch_parent'),
1129 switch_parent=opts.get('switch_parent'),
1130 opts=patch.diffopts(ui, opts))
1130 opts=patch.diffopts(ui, opts))
1131
1131
1132 def forget(ui, repo, *pats, **opts):
1132 def forget(ui, repo, *pats, **opts):
1133 """forget the specified files on the next commit
1133 """forget the specified files on the next commit
1134
1134
1135 Mark the specified files so they will no longer be tracked after the next
1135 Mark the specified files so they will no longer be tracked after the next
1136 commit.
1136 commit.
1137
1137
1138 This only removes files from the current branch, not from the entire
1138 This only removes files from the current branch, not from the entire
1139 project history, and it does not delete them from the working directory.
1139 project history, and it does not delete them from the working directory.
1140
1140
1141 To undo a forget before the next commit, see hg add.
1141 To undo a forget before the next commit, see hg add.
1142 """
1142 """
1143
1143
1144 if not pats:
1144 if not pats:
1145 raise util.Abort(_('no files specified'))
1145 raise util.Abort(_('no files specified'))
1146
1146
1147 m = cmdutil.match(repo, pats, opts)
1147 m = cmdutil.match(repo, pats, opts)
1148 s = repo.status(match=m, clean=True)
1148 s = repo.status(match=m, clean=True)
1149 forget = sorted(s[0] + s[1] + s[3] + s[6])
1149 forget = sorted(s[0] + s[1] + s[3] + s[6])
1150
1150
1151 for f in m.files():
1151 for f in m.files():
1152 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1152 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1153 ui.warn(_('not removing %s: file is already untracked\n')
1153 ui.warn(_('not removing %s: file is already untracked\n')
1154 % m.rel(f))
1154 % m.rel(f))
1155
1155
1156 for f in forget:
1156 for f in forget:
1157 if ui.verbose or not m.exact(f):
1157 if ui.verbose or not m.exact(f):
1158 ui.status(_('removing %s\n') % m.rel(f))
1158 ui.status(_('removing %s\n') % m.rel(f))
1159
1159
1160 repo.remove(forget, unlink=False)
1160 repo.remove(forget, unlink=False)
1161
1161
1162 def grep(ui, repo, pattern, *pats, **opts):
1162 def grep(ui, repo, pattern, *pats, **opts):
1163 """search for a pattern in specified files and revisions
1163 """search for a pattern in specified files and revisions
1164
1164
1165 Search revisions of files for a regular expression.
1165 Search revisions of files for a regular expression.
1166
1166
1167 This command behaves differently than Unix grep. It only accepts
1167 This command behaves differently than Unix grep. It only accepts
1168 Python/Perl regexps. It searches repository history, not the working
1168 Python/Perl regexps. It searches repository history, not the working
1169 directory. It always prints the revision number in which a match appears.
1169 directory. It always prints the revision number in which a match appears.
1170
1170
1171 By default, grep only prints output for the first revision of a file in
1171 By default, grep only prints output for the first revision of a file in
1172 which it finds a match. To get it to print every revision that contains a
1172 which it finds a match. To get it to print every revision that contains a
1173 change in match status ("-" for a match that becomes a non-match, or "+"
1173 change in match status ("-" for a match that becomes a non-match, or "+"
1174 for a non-match that becomes a match), use the --all flag.
1174 for a non-match that becomes a match), use the --all flag.
1175 """
1175 """
1176 reflags = 0
1176 reflags = 0
1177 if opts.get('ignore_case'):
1177 if opts.get('ignore_case'):
1178 reflags |= re.I
1178 reflags |= re.I
1179 try:
1179 try:
1180 regexp = re.compile(pattern, reflags)
1180 regexp = re.compile(pattern, reflags)
1181 except Exception, inst:
1181 except Exception, inst:
1182 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1182 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1183 return None
1183 return None
1184 sep, eol = ':', '\n'
1184 sep, eol = ':', '\n'
1185 if opts.get('print0'):
1185 if opts.get('print0'):
1186 sep = eol = '\0'
1186 sep = eol = '\0'
1187
1187
1188 getfile = util.lrucachefunc(repo.file)
1188 getfile = util.lrucachefunc(repo.file)
1189
1189
1190 def matchlines(body):
1190 def matchlines(body):
1191 begin = 0
1191 begin = 0
1192 linenum = 0
1192 linenum = 0
1193 while True:
1193 while True:
1194 match = regexp.search(body, begin)
1194 match = regexp.search(body, begin)
1195 if not match:
1195 if not match:
1196 break
1196 break
1197 mstart, mend = match.span()
1197 mstart, mend = match.span()
1198 linenum += body.count('\n', begin, mstart) + 1
1198 linenum += body.count('\n', begin, mstart) + 1
1199 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1199 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1200 begin = body.find('\n', mend) + 1 or len(body)
1200 begin = body.find('\n', mend) + 1 or len(body)
1201 lend = begin - 1
1201 lend = begin - 1
1202 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1202 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1203
1203
1204 class linestate(object):
1204 class linestate(object):
1205 def __init__(self, line, linenum, colstart, colend):
1205 def __init__(self, line, linenum, colstart, colend):
1206 self.line = line
1206 self.line = line
1207 self.linenum = linenum
1207 self.linenum = linenum
1208 self.colstart = colstart
1208 self.colstart = colstart
1209 self.colend = colend
1209 self.colend = colend
1210
1210
1211 def __hash__(self):
1211 def __hash__(self):
1212 return hash((self.linenum, self.line))
1212 return hash((self.linenum, self.line))
1213
1213
1214 def __eq__(self, other):
1214 def __eq__(self, other):
1215 return self.line == other.line
1215 return self.line == other.line
1216
1216
1217 matches = {}
1217 matches = {}
1218 copies = {}
1218 copies = {}
1219 def grepbody(fn, rev, body):
1219 def grepbody(fn, rev, body):
1220 matches[rev].setdefault(fn, [])
1220 matches[rev].setdefault(fn, [])
1221 m = matches[rev][fn]
1221 m = matches[rev][fn]
1222 for lnum, cstart, cend, line in matchlines(body):
1222 for lnum, cstart, cend, line in matchlines(body):
1223 s = linestate(line, lnum, cstart, cend)
1223 s = linestate(line, lnum, cstart, cend)
1224 m.append(s)
1224 m.append(s)
1225
1225
1226 def difflinestates(a, b):
1226 def difflinestates(a, b):
1227 sm = difflib.SequenceMatcher(None, a, b)
1227 sm = difflib.SequenceMatcher(None, a, b)
1228 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1228 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1229 if tag == 'insert':
1229 if tag == 'insert':
1230 for i in xrange(blo, bhi):
1230 for i in xrange(blo, bhi):
1231 yield ('+', b[i])
1231 yield ('+', b[i])
1232 elif tag == 'delete':
1232 elif tag == 'delete':
1233 for i in xrange(alo, ahi):
1233 for i in xrange(alo, ahi):
1234 yield ('-', a[i])
1234 yield ('-', a[i])
1235 elif tag == 'replace':
1235 elif tag == 'replace':
1236 for i in xrange(alo, ahi):
1236 for i in xrange(alo, ahi):
1237 yield ('-', a[i])
1237 yield ('-', a[i])
1238 for i in xrange(blo, bhi):
1238 for i in xrange(blo, bhi):
1239 yield ('+', b[i])
1239 yield ('+', b[i])
1240
1240
1241 def display(fn, r, pstates, states):
1241 def display(fn, r, pstates, states):
1242 datefunc = ui.quiet and util.shortdate or util.datestr
1242 datefunc = ui.quiet and util.shortdate or util.datestr
1243 found = False
1243 found = False
1244 filerevmatches = {}
1244 filerevmatches = {}
1245 if opts.get('all'):
1245 if opts.get('all'):
1246 iter = difflinestates(pstates, states)
1246 iter = difflinestates(pstates, states)
1247 else:
1247 else:
1248 iter = [('', l) for l in states]
1248 iter = [('', l) for l in states]
1249 for change, l in iter:
1249 for change, l in iter:
1250 cols = [fn, str(r)]
1250 cols = [fn, str(r)]
1251 if opts.get('line_number'):
1251 if opts.get('line_number'):
1252 cols.append(str(l.linenum))
1252 cols.append(str(l.linenum))
1253 if opts.get('all'):
1253 if opts.get('all'):
1254 cols.append(change)
1254 cols.append(change)
1255 if opts.get('user'):
1255 if opts.get('user'):
1256 cols.append(ui.shortuser(get(r)[1]))
1256 cols.append(ui.shortuser(get(r)[1]))
1257 if opts.get('date'):
1257 if opts.get('date'):
1258 cols.append(datefunc(get(r)[2]))
1258 cols.append(datefunc(get(r)[2]))
1259 if opts.get('files_with_matches'):
1259 if opts.get('files_with_matches'):
1260 c = (fn, r)
1260 c = (fn, r)
1261 if c in filerevmatches:
1261 if c in filerevmatches:
1262 continue
1262 continue
1263 filerevmatches[c] = 1
1263 filerevmatches[c] = 1
1264 else:
1264 else:
1265 cols.append(l.line)
1265 cols.append(l.line)
1266 ui.write(sep.join(cols), eol)
1266 ui.write(sep.join(cols), eol)
1267 found = True
1267 found = True
1268 return found
1268 return found
1269
1269
1270 skip = {}
1270 skip = {}
1271 revfiles = {}
1271 revfiles = {}
1272 get = util.cachefunc(lambda r: repo[r].changeset())
1272 get = util.cachefunc(lambda r: repo[r].changeset())
1273 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1273 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1274 found = False
1274 found = False
1275 follow = opts.get('follow')
1275 follow = opts.get('follow')
1276 for st, rev, fns in changeiter:
1276 for st, rev, fns in changeiter:
1277 if st == 'window':
1277 if st == 'window':
1278 matches.clear()
1278 matches.clear()
1279 revfiles.clear()
1279 revfiles.clear()
1280 elif st == 'add':
1280 elif st == 'add':
1281 ctx = repo[rev]
1281 ctx = repo[rev]
1282 pctx = ctx.parents()[0]
1282 pctx = ctx.parents()[0]
1283 parent = pctx.rev()
1283 parent = pctx.rev()
1284 matches.setdefault(rev, {})
1284 matches.setdefault(rev, {})
1285 matches.setdefault(parent, {})
1285 matches.setdefault(parent, {})
1286 files = revfiles.setdefault(rev, [])
1286 files = revfiles.setdefault(rev, [])
1287 for fn in fns:
1287 for fn in fns:
1288 flog = getfile(fn)
1288 flog = getfile(fn)
1289 try:
1289 try:
1290 fnode = ctx.filenode(fn)
1290 fnode = ctx.filenode(fn)
1291 except error.LookupError:
1291 except error.LookupError:
1292 continue
1292 continue
1293
1293
1294 copied = flog.renamed(fnode)
1294 copied = flog.renamed(fnode)
1295 copy = follow and copied and copied[0]
1295 copy = follow and copied and copied[0]
1296 if copy:
1296 if copy:
1297 copies.setdefault(rev, {})[fn] = copy
1297 copies.setdefault(rev, {})[fn] = copy
1298 if fn in skip:
1298 if fn in skip:
1299 if copy:
1299 if copy:
1300 skip[copy] = True
1300 skip[copy] = True
1301 continue
1301 continue
1302 files.append(fn)
1302 files.append(fn)
1303
1303
1304 if not matches[rev].has_key(fn):
1304 if not matches[rev].has_key(fn):
1305 grepbody(fn, rev, flog.read(fnode))
1305 grepbody(fn, rev, flog.read(fnode))
1306
1306
1307 pfn = copy or fn
1307 pfn = copy or fn
1308 if not matches[parent].has_key(pfn):
1308 if not matches[parent].has_key(pfn):
1309 try:
1309 try:
1310 fnode = pctx.filenode(pfn)
1310 fnode = pctx.filenode(pfn)
1311 grepbody(pfn, parent, flog.read(fnode))
1311 grepbody(pfn, parent, flog.read(fnode))
1312 except error.LookupError:
1312 except error.LookupError:
1313 pass
1313 pass
1314 elif st == 'iter':
1314 elif st == 'iter':
1315 parent = repo[rev].parents()[0].rev()
1315 parent = repo[rev].parents()[0].rev()
1316 for fn in sorted(revfiles.get(rev, [])):
1316 for fn in sorted(revfiles.get(rev, [])):
1317 states = matches[rev][fn]
1317 states = matches[rev][fn]
1318 copy = copies.get(rev, {}).get(fn)
1318 copy = copies.get(rev, {}).get(fn)
1319 if fn in skip:
1319 if fn in skip:
1320 if copy:
1320 if copy:
1321 skip[copy] = True
1321 skip[copy] = True
1322 continue
1322 continue
1323 pstates = matches.get(parent, {}).get(copy or fn, [])
1323 pstates = matches.get(parent, {}).get(copy or fn, [])
1324 if pstates or states:
1324 if pstates or states:
1325 r = display(fn, rev, pstates, states)
1325 r = display(fn, rev, pstates, states)
1326 found = found or r
1326 found = found or r
1327 if r and not opts.get('all'):
1327 if r and not opts.get('all'):
1328 skip[fn] = True
1328 skip[fn] = True
1329 if copy:
1329 if copy:
1330 skip[copy] = True
1330 skip[copy] = True
1331
1331
1332 def heads(ui, repo, *branchrevs, **opts):
1332 def heads(ui, repo, *branchrevs, **opts):
1333 """show current repository heads or show branch heads
1333 """show current repository heads or show branch heads
1334
1334
1335 With no arguments, show all repository head changesets.
1335 With no arguments, show all repository head changesets.
1336
1336
1337 Repository "heads" are changesets that don't have child changesets. They
1337 Repository "heads" are changesets that don't have child changesets. They
1338 are where development generally takes place and are the usual targets for
1338 are where development generally takes place and are the usual targets for
1339 update and merge operations.
1339 update and merge operations.
1340
1340
1341 If one or more REV is given, the "branch heads" will be shown for the
1341 If one or more REV is given, the "branch heads" will be shown for the
1342 named branch associated with that revision. The name of the branch is
1342 named branch associated with that revision. The name of the branch is
1343 called the revision's branch tag.
1343 called the revision's branch tag.
1344
1344
1345 Branch heads are revisions on a given named branch that do not have any
1345 Branch heads are revisions on a given named branch that do not have any
1346 descendants on the same branch. A branch head could be a true head or it
1346 descendants on the same branch. A branch head could be a true head or it
1347 could be the last changeset on a branch before a new branch was created.
1347 could be the last changeset on a branch before a new branch was created.
1348 If none of the branch heads are true heads, the branch is considered
1348 If none of the branch heads are true heads, the branch is considered
1349 inactive. If -c/--closed is specified, also show branch heads marked
1349 inactive. If -c/--closed is specified, also show branch heads marked
1350 closed (see hg commit --close-branch).
1350 closed (see hg commit --close-branch).
1351
1351
1352 If STARTREV is specified only those heads (or branch heads) that are
1352 If STARTREV is specified only those heads (or branch heads) that are
1353 descendants of STARTREV will be displayed.
1353 descendants of STARTREV will be displayed.
1354 """
1354 """
1355 if opts.get('rev'):
1355 if opts.get('rev'):
1356 start = repo.lookup(opts['rev'])
1356 start = repo.lookup(opts['rev'])
1357 else:
1357 else:
1358 start = None
1358 start = None
1359 closed = opts.get('closed')
1359 closed = opts.get('closed')
1360 hideinactive, _heads = opts.get('active'), None
1360 hideinactive, _heads = opts.get('active'), None
1361 if not branchrevs:
1361 if not branchrevs:
1362 if closed:
1363 raise error.Abort(_('you must specify a branch to use --closed'))
1362 # Assume we're looking repo-wide heads if no revs were specified.
1364 # Assume we're looking repo-wide heads if no revs were specified.
1363 heads = repo.heads(start)
1365 heads = repo.heads(start)
1364 else:
1366 else:
1365 if hideinactive:
1367 if hideinactive:
1366 _heads = repo.heads(start)
1368 _heads = repo.heads(start)
1367 heads = []
1369 heads = []
1368 visitedset = set()
1370 visitedset = set()
1369 for branchrev in branchrevs:
1371 for branchrev in branchrevs:
1370 branch = repo[branchrev].branch()
1372 branch = repo[branchrev].branch()
1371 if branch in visitedset:
1373 if branch in visitedset:
1372 continue
1374 continue
1373 visitedset.add(branch)
1375 visitedset.add(branch)
1374 bheads = repo.branchheads(branch, start, closed=closed)
1376 bheads = repo.branchheads(branch, start, closed=closed)
1375 if not bheads:
1377 if not bheads:
1376 if not opts.get('rev'):
1378 if not opts.get('rev'):
1377 ui.warn(_("no open branch heads on branch %s\n") % branch)
1379 ui.warn(_("no open branch heads on branch %s\n") % branch)
1378 elif branch != branchrev:
1380 elif branch != branchrev:
1379 ui.warn(_("no changes on branch %s containing %s are "
1381 ui.warn(_("no changes on branch %s containing %s are "
1380 "reachable from %s\n")
1382 "reachable from %s\n")
1381 % (branch, branchrev, opts.get('rev')))
1383 % (branch, branchrev, opts.get('rev')))
1382 else:
1384 else:
1383 ui.warn(_("no changes on branch %s are reachable from %s\n")
1385 ui.warn(_("no changes on branch %s are reachable from %s\n")
1384 % (branch, opts.get('rev')))
1386 % (branch, opts.get('rev')))
1385 if hideinactive:
1387 if hideinactive:
1386 bheads = [bhead for bhead in bheads if bhead in _heads]
1388 bheads = [bhead for bhead in bheads if bhead in _heads]
1387 heads.extend(bheads)
1389 heads.extend(bheads)
1388 if not heads:
1390 if not heads:
1389 return 1
1391 return 1
1390 displayer = cmdutil.show_changeset(ui, repo, opts)
1392 displayer = cmdutil.show_changeset(ui, repo, opts)
1391 for n in heads:
1393 for n in heads:
1392 displayer.show(repo[n])
1394 displayer.show(repo[n])
1393
1395
1394 def help_(ui, name=None, with_version=False):
1396 def help_(ui, name=None, with_version=False):
1395 """show help for a given topic or a help overview
1397 """show help for a given topic or a help overview
1396
1398
1397 With no arguments, print a list of commands with short help messages.
1399 With no arguments, print a list of commands with short help messages.
1398
1400
1399 Given a topic, extension, or command name, print help for that topic.
1401 Given a topic, extension, or command name, print help for that topic.
1400 """
1402 """
1401 option_lists = []
1403 option_lists = []
1402 textwidth = util.termwidth() - 2
1404 textwidth = util.termwidth() - 2
1403
1405
1404 def addglobalopts(aliases):
1406 def addglobalopts(aliases):
1405 if ui.verbose:
1407 if ui.verbose:
1406 option_lists.append((_("global options:"), globalopts))
1408 option_lists.append((_("global options:"), globalopts))
1407 if name == 'shortlist':
1409 if name == 'shortlist':
1408 option_lists.append((_('use "hg help" for the full list '
1410 option_lists.append((_('use "hg help" for the full list '
1409 'of commands'), ()))
1411 'of commands'), ()))
1410 else:
1412 else:
1411 if name == 'shortlist':
1413 if name == 'shortlist':
1412 msg = _('use "hg help" for the full list of commands '
1414 msg = _('use "hg help" for the full list of commands '
1413 'or "hg -v" for details')
1415 'or "hg -v" for details')
1414 elif aliases:
1416 elif aliases:
1415 msg = _('use "hg -v help%s" to show aliases and '
1417 msg = _('use "hg -v help%s" to show aliases and '
1416 'global options') % (name and " " + name or "")
1418 'global options') % (name and " " + name or "")
1417 else:
1419 else:
1418 msg = _('use "hg -v help %s" to show global options') % name
1420 msg = _('use "hg -v help %s" to show global options') % name
1419 option_lists.append((msg, ()))
1421 option_lists.append((msg, ()))
1420
1422
1421 def helpcmd(name):
1423 def helpcmd(name):
1422 if with_version:
1424 if with_version:
1423 version_(ui)
1425 version_(ui)
1424 ui.write('\n')
1426 ui.write('\n')
1425
1427
1426 try:
1428 try:
1427 aliases, i = cmdutil.findcmd(name, table, False)
1429 aliases, i = cmdutil.findcmd(name, table, False)
1428 except error.AmbiguousCommand, inst:
1430 except error.AmbiguousCommand, inst:
1429 # py3k fix: except vars can't be used outside the scope of the
1431 # py3k fix: except vars can't be used outside the scope of the
1430 # except block, nor can be used inside a lambda. python issue4617
1432 # except block, nor can be used inside a lambda. python issue4617
1431 prefix = inst.args[0]
1433 prefix = inst.args[0]
1432 select = lambda c: c.lstrip('^').startswith(prefix)
1434 select = lambda c: c.lstrip('^').startswith(prefix)
1433 helplist(_('list of commands:\n\n'), select)
1435 helplist(_('list of commands:\n\n'), select)
1434 return
1436 return
1435
1437
1436 # synopsis
1438 # synopsis
1437 if len(i) > 2:
1439 if len(i) > 2:
1438 if i[2].startswith('hg'):
1440 if i[2].startswith('hg'):
1439 ui.write("%s\n" % i[2])
1441 ui.write("%s\n" % i[2])
1440 else:
1442 else:
1441 ui.write('hg %s %s\n' % (aliases[0], i[2]))
1443 ui.write('hg %s %s\n' % (aliases[0], i[2]))
1442 else:
1444 else:
1443 ui.write('hg %s\n' % aliases[0])
1445 ui.write('hg %s\n' % aliases[0])
1444
1446
1445 # aliases
1447 # aliases
1446 if not ui.quiet and len(aliases) > 1:
1448 if not ui.quiet and len(aliases) > 1:
1447 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1449 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1448
1450
1449 # description
1451 # description
1450 doc = gettext(i[0].__doc__)
1452 doc = gettext(i[0].__doc__)
1451 if not doc:
1453 if not doc:
1452 doc = _("(no help text available)")
1454 doc = _("(no help text available)")
1453 if ui.quiet:
1455 if ui.quiet:
1454 doc = doc.splitlines()[0]
1456 doc = doc.splitlines()[0]
1455 ui.write("\n%s\n" % minirst.format(doc, textwidth))
1457 ui.write("\n%s\n" % minirst.format(doc, textwidth))
1456
1458
1457 if not ui.quiet:
1459 if not ui.quiet:
1458 # options
1460 # options
1459 if i[1]:
1461 if i[1]:
1460 option_lists.append((_("options:\n"), i[1]))
1462 option_lists.append((_("options:\n"), i[1]))
1461
1463
1462 addglobalopts(False)
1464 addglobalopts(False)
1463
1465
1464 def helplist(header, select=None):
1466 def helplist(header, select=None):
1465 h = {}
1467 h = {}
1466 cmds = {}
1468 cmds = {}
1467 for c, e in table.iteritems():
1469 for c, e in table.iteritems():
1468 f = c.split("|", 1)[0]
1470 f = c.split("|", 1)[0]
1469 if select and not select(f):
1471 if select and not select(f):
1470 continue
1472 continue
1471 if (not select and name != 'shortlist' and
1473 if (not select and name != 'shortlist' and
1472 e[0].__module__ != __name__):
1474 e[0].__module__ != __name__):
1473 continue
1475 continue
1474 if name == "shortlist" and not f.startswith("^"):
1476 if name == "shortlist" and not f.startswith("^"):
1475 continue
1477 continue
1476 f = f.lstrip("^")
1478 f = f.lstrip("^")
1477 if not ui.debugflag and f.startswith("debug"):
1479 if not ui.debugflag and f.startswith("debug"):
1478 continue
1480 continue
1479 doc = e[0].__doc__
1481 doc = e[0].__doc__
1480 if doc and 'DEPRECATED' in doc and not ui.verbose:
1482 if doc and 'DEPRECATED' in doc and not ui.verbose:
1481 continue
1483 continue
1482 doc = gettext(doc)
1484 doc = gettext(doc)
1483 if not doc:
1485 if not doc:
1484 doc = _("(no help text available)")
1486 doc = _("(no help text available)")
1485 h[f] = doc.splitlines()[0].rstrip()
1487 h[f] = doc.splitlines()[0].rstrip()
1486 cmds[f] = c.lstrip("^")
1488 cmds[f] = c.lstrip("^")
1487
1489
1488 if not h:
1490 if not h:
1489 ui.status(_('no commands defined\n'))
1491 ui.status(_('no commands defined\n'))
1490 return
1492 return
1491
1493
1492 ui.status(header)
1494 ui.status(header)
1493 fns = sorted(h)
1495 fns = sorted(h)
1494 m = max(map(len, fns))
1496 m = max(map(len, fns))
1495 for f in fns:
1497 for f in fns:
1496 if ui.verbose:
1498 if ui.verbose:
1497 commands = cmds[f].replace("|",", ")
1499 commands = cmds[f].replace("|",", ")
1498 ui.write(" %s:\n %s\n"%(commands, h[f]))
1500 ui.write(" %s:\n %s\n"%(commands, h[f]))
1499 else:
1501 else:
1500 ui.write(' %-*s %s\n' % (m, f, util.wrap(h[f], m + 4)))
1502 ui.write(' %-*s %s\n' % (m, f, util.wrap(h[f], m + 4)))
1501
1503
1502 if name != 'shortlist':
1504 if name != 'shortlist':
1503 exts, maxlength = extensions.enabled()
1505 exts, maxlength = extensions.enabled()
1504 text = help.listexts(_('enabled extensions:'), exts, maxlength)
1506 text = help.listexts(_('enabled extensions:'), exts, maxlength)
1505 if text:
1507 if text:
1506 ui.write("\n%s\n" % minirst.format(text, textwidth))
1508 ui.write("\n%s\n" % minirst.format(text, textwidth))
1507
1509
1508 if not ui.quiet:
1510 if not ui.quiet:
1509 addglobalopts(True)
1511 addglobalopts(True)
1510
1512
1511 def helptopic(name):
1513 def helptopic(name):
1512 for names, header, doc in help.helptable:
1514 for names, header, doc in help.helptable:
1513 if name in names:
1515 if name in names:
1514 break
1516 break
1515 else:
1517 else:
1516 raise error.UnknownCommand(name)
1518 raise error.UnknownCommand(name)
1517
1519
1518 # description
1520 # description
1519 if not doc:
1521 if not doc:
1520 doc = _("(no help text available)")
1522 doc = _("(no help text available)")
1521 if hasattr(doc, '__call__'):
1523 if hasattr(doc, '__call__'):
1522 doc = doc()
1524 doc = doc()
1523
1525
1524 ui.write("%s\n\n" % header)
1526 ui.write("%s\n\n" % header)
1525 ui.write("%s\n" % minirst.format(doc, textwidth))
1527 ui.write("%s\n" % minirst.format(doc, textwidth))
1526
1528
1527 def helpext(name):
1529 def helpext(name):
1528 try:
1530 try:
1529 mod = extensions.find(name)
1531 mod = extensions.find(name)
1530 except KeyError:
1532 except KeyError:
1531 raise error.UnknownCommand(name)
1533 raise error.UnknownCommand(name)
1532
1534
1533 doc = gettext(mod.__doc__) or _('no help text available')
1535 doc = gettext(mod.__doc__) or _('no help text available')
1534 head, tail = doc.split('\n', 1)
1536 head, tail = doc.split('\n', 1)
1535 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1537 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1536 if tail:
1538 if tail:
1537 ui.write(minirst.format(tail, textwidth))
1539 ui.write(minirst.format(tail, textwidth))
1538 ui.status('\n\n')
1540 ui.status('\n\n')
1539
1541
1540 try:
1542 try:
1541 ct = mod.cmdtable
1543 ct = mod.cmdtable
1542 except AttributeError:
1544 except AttributeError:
1543 ct = {}
1545 ct = {}
1544
1546
1545 modcmds = set([c.split('|', 1)[0] for c in ct])
1547 modcmds = set([c.split('|', 1)[0] for c in ct])
1546 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1548 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1547
1549
1548 if name and name != 'shortlist':
1550 if name and name != 'shortlist':
1549 i = None
1551 i = None
1550 for f in (helptopic, helpcmd, helpext):
1552 for f in (helptopic, helpcmd, helpext):
1551 try:
1553 try:
1552 f(name)
1554 f(name)
1553 i = None
1555 i = None
1554 break
1556 break
1555 except error.UnknownCommand, inst:
1557 except error.UnknownCommand, inst:
1556 i = inst
1558 i = inst
1557 if i:
1559 if i:
1558 raise i
1560 raise i
1559
1561
1560 else:
1562 else:
1561 # program name
1563 # program name
1562 if ui.verbose or with_version:
1564 if ui.verbose or with_version:
1563 version_(ui)
1565 version_(ui)
1564 else:
1566 else:
1565 ui.status(_("Mercurial Distributed SCM\n"))
1567 ui.status(_("Mercurial Distributed SCM\n"))
1566 ui.status('\n')
1568 ui.status('\n')
1567
1569
1568 # list of commands
1570 # list of commands
1569 if name == "shortlist":
1571 if name == "shortlist":
1570 header = _('basic commands:\n\n')
1572 header = _('basic commands:\n\n')
1571 else:
1573 else:
1572 header = _('list of commands:\n\n')
1574 header = _('list of commands:\n\n')
1573
1575
1574 helplist(header)
1576 helplist(header)
1575
1577
1576 # list all option lists
1578 # list all option lists
1577 opt_output = []
1579 opt_output = []
1578 for title, options in option_lists:
1580 for title, options in option_lists:
1579 opt_output.append(("\n%s" % title, None))
1581 opt_output.append(("\n%s" % title, None))
1580 for shortopt, longopt, default, desc in options:
1582 for shortopt, longopt, default, desc in options:
1581 if "DEPRECATED" in desc and not ui.verbose: continue
1583 if "DEPRECATED" in desc and not ui.verbose: continue
1582 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1584 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1583 longopt and " --%s" % longopt),
1585 longopt and " --%s" % longopt),
1584 "%s%s" % (desc,
1586 "%s%s" % (desc,
1585 default
1587 default
1586 and _(" (default: %s)") % default
1588 and _(" (default: %s)") % default
1587 or "")))
1589 or "")))
1588
1590
1589 if not name:
1591 if not name:
1590 ui.write(_("\nadditional help topics:\n\n"))
1592 ui.write(_("\nadditional help topics:\n\n"))
1591 topics = []
1593 topics = []
1592 for names, header, doc in help.helptable:
1594 for names, header, doc in help.helptable:
1593 names = [(-len(name), name) for name in names]
1595 names = [(-len(name), name) for name in names]
1594 names.sort()
1596 names.sort()
1595 topics.append((names[0][1], header))
1597 topics.append((names[0][1], header))
1596 topics_len = max([len(s[0]) for s in topics])
1598 topics_len = max([len(s[0]) for s in topics])
1597 for t, desc in topics:
1599 for t, desc in topics:
1598 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1600 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1599
1601
1600 if opt_output:
1602 if opt_output:
1601 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1603 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1602 for first, second in opt_output:
1604 for first, second in opt_output:
1603 if second:
1605 if second:
1604 second = util.wrap(second, opts_len + 3)
1606 second = util.wrap(second, opts_len + 3)
1605 ui.write(" %-*s %s\n" % (opts_len, first, second))
1607 ui.write(" %-*s %s\n" % (opts_len, first, second))
1606 else:
1608 else:
1607 ui.write("%s\n" % first)
1609 ui.write("%s\n" % first)
1608
1610
1609 def identify(ui, repo, source=None,
1611 def identify(ui, repo, source=None,
1610 rev=None, num=None, id=None, branch=None, tags=None):
1612 rev=None, num=None, id=None, branch=None, tags=None):
1611 """identify the working copy or specified revision
1613 """identify the working copy or specified revision
1612
1614
1613 With no revision, print a summary of the current state of the repository.
1615 With no revision, print a summary of the current state of the repository.
1614
1616
1615 Specifying a path to a repository root or Mercurial bundle will cause
1617 Specifying a path to a repository root or Mercurial bundle will cause
1616 lookup to operate on that repository/bundle.
1618 lookup to operate on that repository/bundle.
1617
1619
1618 This summary identifies the repository state using one or two parent hash
1620 This summary identifies the repository state using one or two parent hash
1619 identifiers, followed by a "+" if there are uncommitted changes in the
1621 identifiers, followed by a "+" if there are uncommitted changes in the
1620 working directory, a list of tags for this revision and a branch name for
1622 working directory, a list of tags for this revision and a branch name for
1621 non-default branches.
1623 non-default branches.
1622 """
1624 """
1623
1625
1624 if not repo and not source:
1626 if not repo and not source:
1625 raise util.Abort(_("There is no Mercurial repository here "
1627 raise util.Abort(_("There is no Mercurial repository here "
1626 "(.hg not found)"))
1628 "(.hg not found)"))
1627
1629
1628 hexfunc = ui.debugflag and hex or short
1630 hexfunc = ui.debugflag and hex or short
1629 default = not (num or id or branch or tags)
1631 default = not (num or id or branch or tags)
1630 output = []
1632 output = []
1631
1633
1632 revs = []
1634 revs = []
1633 if source:
1635 if source:
1634 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1636 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1635 repo = hg.repository(ui, source)
1637 repo = hg.repository(ui, source)
1636
1638
1637 if not repo.local():
1639 if not repo.local():
1638 if not rev and revs:
1640 if not rev and revs:
1639 rev = revs[0]
1641 rev = revs[0]
1640 if not rev:
1642 if not rev:
1641 rev = "tip"
1643 rev = "tip"
1642 if num or branch or tags:
1644 if num or branch or tags:
1643 raise util.Abort(
1645 raise util.Abort(
1644 "can't query remote revision number, branch, or tags")
1646 "can't query remote revision number, branch, or tags")
1645 output = [hexfunc(repo.lookup(rev))]
1647 output = [hexfunc(repo.lookup(rev))]
1646 elif not rev:
1648 elif not rev:
1647 ctx = repo[None]
1649 ctx = repo[None]
1648 parents = ctx.parents()
1650 parents = ctx.parents()
1649 changed = False
1651 changed = False
1650 if default or id or num:
1652 if default or id or num:
1651 changed = ctx.files() + ctx.deleted()
1653 changed = ctx.files() + ctx.deleted()
1652 if default or id:
1654 if default or id:
1653 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1655 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1654 (changed) and "+" or "")]
1656 (changed) and "+" or "")]
1655 if num:
1657 if num:
1656 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1658 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1657 (changed) and "+" or ""))
1659 (changed) and "+" or ""))
1658 else:
1660 else:
1659 ctx = repo[rev]
1661 ctx = repo[rev]
1660 if default or id:
1662 if default or id:
1661 output = [hexfunc(ctx.node())]
1663 output = [hexfunc(ctx.node())]
1662 if num:
1664 if num:
1663 output.append(str(ctx.rev()))
1665 output.append(str(ctx.rev()))
1664
1666
1665 if repo.local() and default and not ui.quiet:
1667 if repo.local() and default and not ui.quiet:
1666 b = encoding.tolocal(ctx.branch())
1668 b = encoding.tolocal(ctx.branch())
1667 if b != 'default':
1669 if b != 'default':
1668 output.append("(%s)" % b)
1670 output.append("(%s)" % b)
1669
1671
1670 # multiple tags for a single parent separated by '/'
1672 # multiple tags for a single parent separated by '/'
1671 t = "/".join(ctx.tags())
1673 t = "/".join(ctx.tags())
1672 if t:
1674 if t:
1673 output.append(t)
1675 output.append(t)
1674
1676
1675 if branch:
1677 if branch:
1676 output.append(encoding.tolocal(ctx.branch()))
1678 output.append(encoding.tolocal(ctx.branch()))
1677
1679
1678 if tags:
1680 if tags:
1679 output.extend(ctx.tags())
1681 output.extend(ctx.tags())
1680
1682
1681 ui.write("%s\n" % ' '.join(output))
1683 ui.write("%s\n" % ' '.join(output))
1682
1684
1683 def import_(ui, repo, patch1, *patches, **opts):
1685 def import_(ui, repo, patch1, *patches, **opts):
1684 """import an ordered set of patches
1686 """import an ordered set of patches
1685
1687
1686 Import a list of patches and commit them individually.
1688 Import a list of patches and commit them individually.
1687
1689
1688 If there are outstanding changes in the working directory, import will
1690 If there are outstanding changes in the working directory, import will
1689 abort unless given the -f/--force flag.
1691 abort unless given the -f/--force flag.
1690
1692
1691 You can import a patch straight from a mail message. Even patches as
1693 You can import a patch straight from a mail message. Even patches as
1692 attachments work (to use the body part, it must have type text/plain or
1694 attachments work (to use the body part, it must have type text/plain or
1693 text/x-patch). From and Subject headers of email message are used as
1695 text/x-patch). From and Subject headers of email message are used as
1694 default committer and commit message. All text/plain body parts before
1696 default committer and commit message. All text/plain body parts before
1695 first diff are added to commit message.
1697 first diff are added to commit message.
1696
1698
1697 If the imported patch was generated by hg export, user and description
1699 If the imported patch was generated by hg export, user and description
1698 from patch override values from message headers and body. Values given on
1700 from patch override values from message headers and body. Values given on
1699 command line with -m/--message and -u/--user override these.
1701 command line with -m/--message and -u/--user override these.
1700
1702
1701 If --exact is specified, import will set the working directory to the
1703 If --exact is specified, import will set the working directory to the
1702 parent of each patch before applying it, and will abort if the resulting
1704 parent of each patch before applying it, and will abort if the resulting
1703 changeset has a different ID than the one recorded in the patch. This may
1705 changeset has a different ID than the one recorded in the patch. This may
1704 happen due to character set problems or other deficiencies in the text
1706 happen due to character set problems or other deficiencies in the text
1705 patch format.
1707 patch format.
1706
1708
1707 With -s/--similarity, hg will attempt to discover renames and copies in
1709 With -s/--similarity, hg will attempt to discover renames and copies in
1708 the patch in the same way as 'addremove'.
1710 the patch in the same way as 'addremove'.
1709
1711
1710 To read a patch from standard input, use "-" as the patch name. If a URL
1712 To read a patch from standard input, use "-" as the patch name. If a URL
1711 is specified, the patch will be downloaded from it. See 'hg help dates'
1713 is specified, the patch will be downloaded from it. See 'hg help dates'
1712 for a list of formats valid for -d/--date.
1714 for a list of formats valid for -d/--date.
1713 """
1715 """
1714 patches = (patch1,) + patches
1716 patches = (patch1,) + patches
1715
1717
1716 date = opts.get('date')
1718 date = opts.get('date')
1717 if date:
1719 if date:
1718 opts['date'] = util.parsedate(date)
1720 opts['date'] = util.parsedate(date)
1719
1721
1720 try:
1722 try:
1721 sim = float(opts.get('similarity') or 0)
1723 sim = float(opts.get('similarity') or 0)
1722 except ValueError:
1724 except ValueError:
1723 raise util.Abort(_('similarity must be a number'))
1725 raise util.Abort(_('similarity must be a number'))
1724 if sim < 0 or sim > 100:
1726 if sim < 0 or sim > 100:
1725 raise util.Abort(_('similarity must be between 0 and 100'))
1727 raise util.Abort(_('similarity must be between 0 and 100'))
1726
1728
1727 if opts.get('exact') or not opts.get('force'):
1729 if opts.get('exact') or not opts.get('force'):
1728 cmdutil.bail_if_changed(repo)
1730 cmdutil.bail_if_changed(repo)
1729
1731
1730 d = opts["base"]
1732 d = opts["base"]
1731 strip = opts["strip"]
1733 strip = opts["strip"]
1732 wlock = lock = None
1734 wlock = lock = None
1733 try:
1735 try:
1734 wlock = repo.wlock()
1736 wlock = repo.wlock()
1735 lock = repo.lock()
1737 lock = repo.lock()
1736 for p in patches:
1738 for p in patches:
1737 pf = os.path.join(d, p)
1739 pf = os.path.join(d, p)
1738
1740
1739 if pf == '-':
1741 if pf == '-':
1740 ui.status(_("applying patch from stdin\n"))
1742 ui.status(_("applying patch from stdin\n"))
1741 pf = sys.stdin
1743 pf = sys.stdin
1742 else:
1744 else:
1743 ui.status(_("applying %s\n") % p)
1745 ui.status(_("applying %s\n") % p)
1744 pf = url.open(ui, pf)
1746 pf = url.open(ui, pf)
1745 data = patch.extract(ui, pf)
1747 data = patch.extract(ui, pf)
1746 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1748 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1747
1749
1748 if tmpname is None:
1750 if tmpname is None:
1749 raise util.Abort(_('no diffs found'))
1751 raise util.Abort(_('no diffs found'))
1750
1752
1751 try:
1753 try:
1752 cmdline_message = cmdutil.logmessage(opts)
1754 cmdline_message = cmdutil.logmessage(opts)
1753 if cmdline_message:
1755 if cmdline_message:
1754 # pickup the cmdline msg
1756 # pickup the cmdline msg
1755 message = cmdline_message
1757 message = cmdline_message
1756 elif message:
1758 elif message:
1757 # pickup the patch msg
1759 # pickup the patch msg
1758 message = message.strip()
1760 message = message.strip()
1759 else:
1761 else:
1760 # launch the editor
1762 # launch the editor
1761 message = None
1763 message = None
1762 ui.debug(_('message:\n%s\n') % message)
1764 ui.debug(_('message:\n%s\n') % message)
1763
1765
1764 wp = repo.parents()
1766 wp = repo.parents()
1765 if opts.get('exact'):
1767 if opts.get('exact'):
1766 if not nodeid or not p1:
1768 if not nodeid or not p1:
1767 raise util.Abort(_('not a Mercurial patch'))
1769 raise util.Abort(_('not a Mercurial patch'))
1768 p1 = repo.lookup(p1)
1770 p1 = repo.lookup(p1)
1769 p2 = repo.lookup(p2 or hex(nullid))
1771 p2 = repo.lookup(p2 or hex(nullid))
1770
1772
1771 if p1 != wp[0].node():
1773 if p1 != wp[0].node():
1772 hg.clean(repo, p1)
1774 hg.clean(repo, p1)
1773 repo.dirstate.setparents(p1, p2)
1775 repo.dirstate.setparents(p1, p2)
1774 elif p2:
1776 elif p2:
1775 try:
1777 try:
1776 p1 = repo.lookup(p1)
1778 p1 = repo.lookup(p1)
1777 p2 = repo.lookup(p2)
1779 p2 = repo.lookup(p2)
1778 if p1 == wp[0].node():
1780 if p1 == wp[0].node():
1779 repo.dirstate.setparents(p1, p2)
1781 repo.dirstate.setparents(p1, p2)
1780 except error.RepoError:
1782 except error.RepoError:
1781 pass
1783 pass
1782 if opts.get('exact') or opts.get('import_branch'):
1784 if opts.get('exact') or opts.get('import_branch'):
1783 repo.dirstate.setbranch(branch or 'default')
1785 repo.dirstate.setbranch(branch or 'default')
1784
1786
1785 files = {}
1787 files = {}
1786 try:
1788 try:
1787 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1789 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1788 files=files, eolmode=None)
1790 files=files, eolmode=None)
1789 finally:
1791 finally:
1790 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1792 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1791 if not opts.get('no_commit'):
1793 if not opts.get('no_commit'):
1792 m = cmdutil.matchfiles(repo, files or [])
1794 m = cmdutil.matchfiles(repo, files or [])
1793 n = repo.commit(message, opts.get('user') or user,
1795 n = repo.commit(message, opts.get('user') or user,
1794 opts.get('date') or date, match=m,
1796 opts.get('date') or date, match=m,
1795 editor=cmdutil.commiteditor)
1797 editor=cmdutil.commiteditor)
1796 if opts.get('exact'):
1798 if opts.get('exact'):
1797 if hex(n) != nodeid:
1799 if hex(n) != nodeid:
1798 repo.rollback()
1800 repo.rollback()
1799 raise util.Abort(_('patch is damaged'
1801 raise util.Abort(_('patch is damaged'
1800 ' or loses information'))
1802 ' or loses information'))
1801 # Force a dirstate write so that the next transaction
1803 # Force a dirstate write so that the next transaction
1802 # backups an up-do-date file.
1804 # backups an up-do-date file.
1803 repo.dirstate.write()
1805 repo.dirstate.write()
1804 finally:
1806 finally:
1805 os.unlink(tmpname)
1807 os.unlink(tmpname)
1806 finally:
1808 finally:
1807 release(lock, wlock)
1809 release(lock, wlock)
1808
1810
1809 def incoming(ui, repo, source="default", **opts):
1811 def incoming(ui, repo, source="default", **opts):
1810 """show new changesets found in source
1812 """show new changesets found in source
1811
1813
1812 Show new changesets found in the specified path/URL or the default pull
1814 Show new changesets found in the specified path/URL or the default pull
1813 location. These are the changesets that would have been pulled if a pull
1815 location. These are the changesets that would have been pulled if a pull
1814 at the time you issued this command.
1816 at the time you issued this command.
1815
1817
1816 For remote repository, using --bundle avoids downloading the changesets
1818 For remote repository, using --bundle avoids downloading the changesets
1817 twice if the incoming is followed by a pull.
1819 twice if the incoming is followed by a pull.
1818
1820
1819 See pull for valid source format details.
1821 See pull for valid source format details.
1820 """
1822 """
1821 limit = cmdutil.loglimit(opts)
1823 limit = cmdutil.loglimit(opts)
1822 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1824 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1823 other = hg.repository(cmdutil.remoteui(repo, opts), source)
1825 other = hg.repository(cmdutil.remoteui(repo, opts), source)
1824 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1826 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1825 if revs:
1827 if revs:
1826 revs = [other.lookup(rev) for rev in revs]
1828 revs = [other.lookup(rev) for rev in revs]
1827 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1829 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1828 force=opts["force"])
1830 force=opts["force"])
1829 if not incoming:
1831 if not incoming:
1830 try:
1832 try:
1831 os.unlink(opts["bundle"])
1833 os.unlink(opts["bundle"])
1832 except:
1834 except:
1833 pass
1835 pass
1834 ui.status(_("no changes found\n"))
1836 ui.status(_("no changes found\n"))
1835 return 1
1837 return 1
1836
1838
1837 cleanup = None
1839 cleanup = None
1838 try:
1840 try:
1839 fname = opts["bundle"]
1841 fname = opts["bundle"]
1840 if fname or not other.local():
1842 if fname or not other.local():
1841 # create a bundle (uncompressed if other repo is not local)
1843 # create a bundle (uncompressed if other repo is not local)
1842
1844
1843 if revs is None and other.capable('changegroupsubset'):
1845 if revs is None and other.capable('changegroupsubset'):
1844 revs = rheads
1846 revs = rheads
1845
1847
1846 if revs is None:
1848 if revs is None:
1847 cg = other.changegroup(incoming, "incoming")
1849 cg = other.changegroup(incoming, "incoming")
1848 else:
1850 else:
1849 cg = other.changegroupsubset(incoming, revs, 'incoming')
1851 cg = other.changegroupsubset(incoming, revs, 'incoming')
1850 bundletype = other.local() and "HG10BZ" or "HG10UN"
1852 bundletype = other.local() and "HG10BZ" or "HG10UN"
1851 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1853 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1852 # keep written bundle?
1854 # keep written bundle?
1853 if opts["bundle"]:
1855 if opts["bundle"]:
1854 cleanup = None
1856 cleanup = None
1855 if not other.local():
1857 if not other.local():
1856 # use the created uncompressed bundlerepo
1858 # use the created uncompressed bundlerepo
1857 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1859 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1858
1860
1859 o = other.changelog.nodesbetween(incoming, revs)[0]
1861 o = other.changelog.nodesbetween(incoming, revs)[0]
1860 if opts.get('newest_first'):
1862 if opts.get('newest_first'):
1861 o.reverse()
1863 o.reverse()
1862 displayer = cmdutil.show_changeset(ui, other, opts)
1864 displayer = cmdutil.show_changeset(ui, other, opts)
1863 count = 0
1865 count = 0
1864 for n in o:
1866 for n in o:
1865 if count >= limit:
1867 if count >= limit:
1866 break
1868 break
1867 parents = [p for p in other.changelog.parents(n) if p != nullid]
1869 parents = [p for p in other.changelog.parents(n) if p != nullid]
1868 if opts.get('no_merges') and len(parents) == 2:
1870 if opts.get('no_merges') and len(parents) == 2:
1869 continue
1871 continue
1870 count += 1
1872 count += 1
1871 displayer.show(other[n])
1873 displayer.show(other[n])
1872 finally:
1874 finally:
1873 if hasattr(other, 'close'):
1875 if hasattr(other, 'close'):
1874 other.close()
1876 other.close()
1875 if cleanup:
1877 if cleanup:
1876 os.unlink(cleanup)
1878 os.unlink(cleanup)
1877
1879
1878 def init(ui, dest=".", **opts):
1880 def init(ui, dest=".", **opts):
1879 """create a new repository in the given directory
1881 """create a new repository in the given directory
1880
1882
1881 Initialize a new repository in the given directory. If the given directory
1883 Initialize a new repository in the given directory. If the given directory
1882 does not exist, it will be created.
1884 does not exist, it will be created.
1883
1885
1884 If no directory is given, the current directory is used.
1886 If no directory is given, the current directory is used.
1885
1887
1886 It is possible to specify an ssh:// URL as the destination. See 'hg help
1888 It is possible to specify an ssh:// URL as the destination. See 'hg help
1887 urls' for more information.
1889 urls' for more information.
1888 """
1890 """
1889 hg.repository(cmdutil.remoteui(ui, opts), dest, create=1)
1891 hg.repository(cmdutil.remoteui(ui, opts), dest, create=1)
1890
1892
1891 def locate(ui, repo, *pats, **opts):
1893 def locate(ui, repo, *pats, **opts):
1892 """locate files matching specific patterns
1894 """locate files matching specific patterns
1893
1895
1894 Print files under Mercurial control in the working directory whose names
1896 Print files under Mercurial control in the working directory whose names
1895 match the given patterns.
1897 match the given patterns.
1896
1898
1897 By default, this command searches all directories in the working
1899 By default, this command searches all directories in the working
1898 directory. To search just the current directory and its subdirectories,
1900 directory. To search just the current directory and its subdirectories,
1899 use "--include .".
1901 use "--include .".
1900
1902
1901 If no patterns are given to match, this command prints the names of all
1903 If no patterns are given to match, this command prints the names of all
1902 files under Mercurial control in the working directory.
1904 files under Mercurial control in the working directory.
1903
1905
1904 If you want to feed the output of this command into the "xargs" command,
1906 If you want to feed the output of this command into the "xargs" command,
1905 use the -0 option to both this command and "xargs". This will avoid the
1907 use the -0 option to both this command and "xargs". This will avoid the
1906 problem of "xargs" treating single filenames that contain whitespace as
1908 problem of "xargs" treating single filenames that contain whitespace as
1907 multiple filenames.
1909 multiple filenames.
1908 """
1910 """
1909 end = opts.get('print0') and '\0' or '\n'
1911 end = opts.get('print0') and '\0' or '\n'
1910 rev = opts.get('rev') or None
1912 rev = opts.get('rev') or None
1911
1913
1912 ret = 1
1914 ret = 1
1913 m = cmdutil.match(repo, pats, opts, default='relglob')
1915 m = cmdutil.match(repo, pats, opts, default='relglob')
1914 m.bad = lambda x,y: False
1916 m.bad = lambda x,y: False
1915 for abs in repo[rev].walk(m):
1917 for abs in repo[rev].walk(m):
1916 if not rev and abs not in repo.dirstate:
1918 if not rev and abs not in repo.dirstate:
1917 continue
1919 continue
1918 if opts.get('fullpath'):
1920 if opts.get('fullpath'):
1919 ui.write(repo.wjoin(abs), end)
1921 ui.write(repo.wjoin(abs), end)
1920 else:
1922 else:
1921 ui.write(((pats and m.rel(abs)) or abs), end)
1923 ui.write(((pats and m.rel(abs)) or abs), end)
1922 ret = 0
1924 ret = 0
1923
1925
1924 return ret
1926 return ret
1925
1927
1926 def log(ui, repo, *pats, **opts):
1928 def log(ui, repo, *pats, **opts):
1927 """show revision history of entire repository or files
1929 """show revision history of entire repository or files
1928
1930
1929 Print the revision history of the specified files or the entire project.
1931 Print the revision history of the specified files or the entire project.
1930
1932
1931 File history is shown without following rename or copy history of files.
1933 File history is shown without following rename or copy history of files.
1932 Use -f/--follow with a filename to follow history across renames and
1934 Use -f/--follow with a filename to follow history across renames and
1933 copies. --follow without a filename will only show ancestors or
1935 copies. --follow without a filename will only show ancestors or
1934 descendants of the starting revision. --follow-first only follows the
1936 descendants of the starting revision. --follow-first only follows the
1935 first parent of merge revisions.
1937 first parent of merge revisions.
1936
1938
1937 If no revision range is specified, the default is tip:0 unless --follow is
1939 If no revision range is specified, the default is tip:0 unless --follow is
1938 set, in which case the working directory parent is used as the starting
1940 set, in which case the working directory parent is used as the starting
1939 revision.
1941 revision.
1940
1942
1941 See 'hg help dates' for a list of formats valid for -d/--date.
1943 See 'hg help dates' for a list of formats valid for -d/--date.
1942
1944
1943 By default this command prints revision number and changeset id, tags,
1945 By default this command prints revision number and changeset id, tags,
1944 non-trivial parents, user, date and time, and a summary for each commit.
1946 non-trivial parents, user, date and time, and a summary for each commit.
1945 When the -v/--verbose switch is used, the list of changed files and full
1947 When the -v/--verbose switch is used, the list of changed files and full
1946 commit message are shown.
1948 commit message are shown.
1947
1949
1948 NOTE: log -p/--patch may generate unexpected diff output for merge
1950 NOTE: log -p/--patch may generate unexpected diff output for merge
1949 changesets, as it will only compare the merge changeset against its first
1951 changesets, as it will only compare the merge changeset against its first
1950 parent. Also, only files different from BOTH parents will appear in
1952 parent. Also, only files different from BOTH parents will appear in
1951 files:.
1953 files:.
1952 """
1954 """
1953
1955
1954 get = util.cachefunc(lambda r: repo[r].changeset())
1956 get = util.cachefunc(lambda r: repo[r].changeset())
1955 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1957 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1956
1958
1957 limit = cmdutil.loglimit(opts)
1959 limit = cmdutil.loglimit(opts)
1958 count = 0
1960 count = 0
1959
1961
1960 if opts.get('copies') and opts.get('rev'):
1962 if opts.get('copies') and opts.get('rev'):
1961 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1963 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1962 else:
1964 else:
1963 endrev = len(repo)
1965 endrev = len(repo)
1964 rcache = {}
1966 rcache = {}
1965 ncache = {}
1967 ncache = {}
1966 def getrenamed(fn, rev):
1968 def getrenamed(fn, rev):
1967 '''looks up all renames for a file (up to endrev) the first
1969 '''looks up all renames for a file (up to endrev) the first
1968 time the file is given. It indexes on the changerev and only
1970 time the file is given. It indexes on the changerev and only
1969 parses the manifest if linkrev != changerev.
1971 parses the manifest if linkrev != changerev.
1970 Returns rename info for fn at changerev rev.'''
1972 Returns rename info for fn at changerev rev.'''
1971 if fn not in rcache:
1973 if fn not in rcache:
1972 rcache[fn] = {}
1974 rcache[fn] = {}
1973 ncache[fn] = {}
1975 ncache[fn] = {}
1974 fl = repo.file(fn)
1976 fl = repo.file(fn)
1975 for i in fl:
1977 for i in fl:
1976 node = fl.node(i)
1978 node = fl.node(i)
1977 lr = fl.linkrev(i)
1979 lr = fl.linkrev(i)
1978 renamed = fl.renamed(node)
1980 renamed = fl.renamed(node)
1979 rcache[fn][lr] = renamed
1981 rcache[fn][lr] = renamed
1980 if renamed:
1982 if renamed:
1981 ncache[fn][node] = renamed
1983 ncache[fn][node] = renamed
1982 if lr >= endrev:
1984 if lr >= endrev:
1983 break
1985 break
1984 if rev in rcache[fn]:
1986 if rev in rcache[fn]:
1985 return rcache[fn][rev]
1987 return rcache[fn][rev]
1986
1988
1987 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1989 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1988 # filectx logic.
1990 # filectx logic.
1989
1991
1990 try:
1992 try:
1991 return repo[rev][fn].renamed()
1993 return repo[rev][fn].renamed()
1992 except error.LookupError:
1994 except error.LookupError:
1993 pass
1995 pass
1994 return None
1996 return None
1995
1997
1996 df = False
1998 df = False
1997 if opts["date"]:
1999 if opts["date"]:
1998 df = util.matchdate(opts["date"])
2000 df = util.matchdate(opts["date"])
1999
2001
2000 only_branches = opts.get('only_branch')
2002 only_branches = opts.get('only_branch')
2001
2003
2002 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
2004 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
2003 for st, rev, fns in changeiter:
2005 for st, rev, fns in changeiter:
2004 if st == 'add':
2006 if st == 'add':
2005 parents = [p for p in repo.changelog.parentrevs(rev)
2007 parents = [p for p in repo.changelog.parentrevs(rev)
2006 if p != nullrev]
2008 if p != nullrev]
2007 if opts.get('no_merges') and len(parents) == 2:
2009 if opts.get('no_merges') and len(parents) == 2:
2008 continue
2010 continue
2009 if opts.get('only_merges') and len(parents) != 2:
2011 if opts.get('only_merges') and len(parents) != 2:
2010 continue
2012 continue
2011
2013
2012 if only_branches:
2014 if only_branches:
2013 revbranch = get(rev)[5]['branch']
2015 revbranch = get(rev)[5]['branch']
2014 if revbranch not in only_branches:
2016 if revbranch not in only_branches:
2015 continue
2017 continue
2016
2018
2017 if df:
2019 if df:
2018 changes = get(rev)
2020 changes = get(rev)
2019 if not df(changes[2][0]):
2021 if not df(changes[2][0]):
2020 continue
2022 continue
2021
2023
2022 if opts.get('keyword'):
2024 if opts.get('keyword'):
2023 changes = get(rev)
2025 changes = get(rev)
2024 miss = 0
2026 miss = 0
2025 for k in [kw.lower() for kw in opts['keyword']]:
2027 for k in [kw.lower() for kw in opts['keyword']]:
2026 if not (k in changes[1].lower() or
2028 if not (k in changes[1].lower() or
2027 k in changes[4].lower() or
2029 k in changes[4].lower() or
2028 k in " ".join(changes[3]).lower()):
2030 k in " ".join(changes[3]).lower()):
2029 miss = 1
2031 miss = 1
2030 break
2032 break
2031 if miss:
2033 if miss:
2032 continue
2034 continue
2033
2035
2034 if opts['user']:
2036 if opts['user']:
2035 changes = get(rev)
2037 changes = get(rev)
2036 if not [k for k in opts['user'] if k in changes[1]]:
2038 if not [k for k in opts['user'] if k in changes[1]]:
2037 continue
2039 continue
2038
2040
2039 copies = []
2041 copies = []
2040 if opts.get('copies') and rev:
2042 if opts.get('copies') and rev:
2041 for fn in get(rev)[3]:
2043 for fn in get(rev)[3]:
2042 rename = getrenamed(fn, rev)
2044 rename = getrenamed(fn, rev)
2043 if rename:
2045 if rename:
2044 copies.append((fn, rename[0]))
2046 copies.append((fn, rename[0]))
2045 displayer.show(context.changectx(repo, rev), copies=copies)
2047 displayer.show(context.changectx(repo, rev), copies=copies)
2046 elif st == 'iter':
2048 elif st == 'iter':
2047 if count == limit: break
2049 if count == limit: break
2048 if displayer.flush(rev):
2050 if displayer.flush(rev):
2049 count += 1
2051 count += 1
2050
2052
2051 def manifest(ui, repo, node=None, rev=None):
2053 def manifest(ui, repo, node=None, rev=None):
2052 """output the current or given revision of the project manifest
2054 """output the current or given revision of the project manifest
2053
2055
2054 Print a list of version controlled files for the given revision. If no
2056 Print a list of version controlled files for the given revision. If no
2055 revision is given, the first parent of the working directory is used, or
2057 revision is given, the first parent of the working directory is used, or
2056 the null revision if no revision is checked out.
2058 the null revision if no revision is checked out.
2057
2059
2058 With -v, print file permissions, symlink and executable bits.
2060 With -v, print file permissions, symlink and executable bits.
2059 With --debug, print file revision hashes.
2061 With --debug, print file revision hashes.
2060 """
2062 """
2061
2063
2062 if rev and node:
2064 if rev and node:
2063 raise util.Abort(_("please specify just one revision"))
2065 raise util.Abort(_("please specify just one revision"))
2064
2066
2065 if not node:
2067 if not node:
2066 node = rev
2068 node = rev
2067
2069
2068 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2070 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2069 ctx = repo[node]
2071 ctx = repo[node]
2070 for f in ctx:
2072 for f in ctx:
2071 if ui.debugflag:
2073 if ui.debugflag:
2072 ui.write("%40s " % hex(ctx.manifest()[f]))
2074 ui.write("%40s " % hex(ctx.manifest()[f]))
2073 if ui.verbose:
2075 if ui.verbose:
2074 ui.write(decor[ctx.flags(f)])
2076 ui.write(decor[ctx.flags(f)])
2075 ui.write("%s\n" % f)
2077 ui.write("%s\n" % f)
2076
2078
2077 def merge(ui, repo, node=None, **opts):
2079 def merge(ui, repo, node=None, **opts):
2078 """merge working directory with another revision
2080 """merge working directory with another revision
2079
2081
2080 The current working directory is updated with all changes made in the
2082 The current working directory is updated with all changes made in the
2081 requested revision since the last common predecessor revision.
2083 requested revision since the last common predecessor revision.
2082
2084
2083 Files that changed between either parent are marked as changed for the
2085 Files that changed between either parent are marked as changed for the
2084 next commit and a commit must be performed before any further updates to
2086 next commit and a commit must be performed before any further updates to
2085 the repository are allowed. The next commit will have two parents.
2087 the repository are allowed. The next commit will have two parents.
2086
2088
2087 If no revision is specified, the working directory's parent is a head
2089 If no revision is specified, the working directory's parent is a head
2088 revision, and the current branch contains exactly one other head, the
2090 revision, and the current branch contains exactly one other head, the
2089 other head is merged with by default. Otherwise, an explicit revision with
2091 other head is merged with by default. Otherwise, an explicit revision with
2090 which to merge with must be provided.
2092 which to merge with must be provided.
2091 """
2093 """
2092
2094
2093 if opts.get('rev') and node:
2095 if opts.get('rev') and node:
2094 raise util.Abort(_("please specify just one revision"))
2096 raise util.Abort(_("please specify just one revision"))
2095 if not node:
2097 if not node:
2096 node = opts.get('rev')
2098 node = opts.get('rev')
2097
2099
2098 if not node:
2100 if not node:
2099 branch = repo.changectx(None).branch()
2101 branch = repo.changectx(None).branch()
2100 bheads = repo.branchheads(branch)
2102 bheads = repo.branchheads(branch)
2101 if len(bheads) > 2:
2103 if len(bheads) > 2:
2102 raise util.Abort(_("branch '%s' has %d heads - "
2104 raise util.Abort(_("branch '%s' has %d heads - "
2103 "please merge with an explicit rev") %
2105 "please merge with an explicit rev") %
2104 (branch, len(bheads)))
2106 (branch, len(bheads)))
2105
2107
2106 parent = repo.dirstate.parents()[0]
2108 parent = repo.dirstate.parents()[0]
2107 if len(bheads) == 1:
2109 if len(bheads) == 1:
2108 if len(repo.heads()) > 1:
2110 if len(repo.heads()) > 1:
2109 raise util.Abort(_("branch '%s' has one head - "
2111 raise util.Abort(_("branch '%s' has one head - "
2110 "please merge with an explicit rev") %
2112 "please merge with an explicit rev") %
2111 branch)
2113 branch)
2112 msg = _('there is nothing to merge')
2114 msg = _('there is nothing to merge')
2113 if parent != repo.lookup(repo[None].branch()):
2115 if parent != repo.lookup(repo[None].branch()):
2114 msg = _('%s - use "hg update" instead') % msg
2116 msg = _('%s - use "hg update" instead') % msg
2115 raise util.Abort(msg)
2117 raise util.Abort(msg)
2116
2118
2117 if parent not in bheads:
2119 if parent not in bheads:
2118 raise util.Abort(_('working dir not at a head rev - '
2120 raise util.Abort(_('working dir not at a head rev - '
2119 'use "hg update" or merge with an explicit rev'))
2121 'use "hg update" or merge with an explicit rev'))
2120 node = parent == bheads[0] and bheads[-1] or bheads[0]
2122 node = parent == bheads[0] and bheads[-1] or bheads[0]
2121
2123
2122 if opts.get('preview'):
2124 if opts.get('preview'):
2123 p1 = repo['.']
2125 p1 = repo['.']
2124 p2 = repo[node]
2126 p2 = repo[node]
2125 common = p1.ancestor(p2)
2127 common = p1.ancestor(p2)
2126 roots, heads = [common.node()], [p2.node()]
2128 roots, heads = [common.node()], [p2.node()]
2127 displayer = cmdutil.show_changeset(ui, repo, opts)
2129 displayer = cmdutil.show_changeset(ui, repo, opts)
2128 for node in repo.changelog.nodesbetween(roots=roots, heads=heads)[0]:
2130 for node in repo.changelog.nodesbetween(roots=roots, heads=heads)[0]:
2129 displayer.show(repo[node])
2131 displayer.show(repo[node])
2130 return 0
2132 return 0
2131
2133
2132 return hg.merge(repo, node, force=opts.get('force'))
2134 return hg.merge(repo, node, force=opts.get('force'))
2133
2135
2134 def outgoing(ui, repo, dest=None, **opts):
2136 def outgoing(ui, repo, dest=None, **opts):
2135 """show changesets not found in destination
2137 """show changesets not found in destination
2136
2138
2137 Show changesets not found in the specified destination repository or the
2139 Show changesets not found in the specified destination repository or the
2138 default push location. These are the changesets that would be pushed if a
2140 default push location. These are the changesets that would be pushed if a
2139 push was requested.
2141 push was requested.
2140
2142
2141 See pull for valid destination format details.
2143 See pull for valid destination format details.
2142 """
2144 """
2143 limit = cmdutil.loglimit(opts)
2145 limit = cmdutil.loglimit(opts)
2144 dest, revs, checkout = hg.parseurl(
2146 dest, revs, checkout = hg.parseurl(
2145 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2147 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2146 if revs:
2148 if revs:
2147 revs = [repo.lookup(rev) for rev in revs]
2149 revs = [repo.lookup(rev) for rev in revs]
2148
2150
2149 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2151 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2150 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2152 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2151 o = repo.findoutgoing(other, force=opts.get('force'))
2153 o = repo.findoutgoing(other, force=opts.get('force'))
2152 if not o:
2154 if not o:
2153 ui.status(_("no changes found\n"))
2155 ui.status(_("no changes found\n"))
2154 return 1
2156 return 1
2155 o = repo.changelog.nodesbetween(o, revs)[0]
2157 o = repo.changelog.nodesbetween(o, revs)[0]
2156 if opts.get('newest_first'):
2158 if opts.get('newest_first'):
2157 o.reverse()
2159 o.reverse()
2158 displayer = cmdutil.show_changeset(ui, repo, opts)
2160 displayer = cmdutil.show_changeset(ui, repo, opts)
2159 count = 0
2161 count = 0
2160 for n in o:
2162 for n in o:
2161 if count >= limit:
2163 if count >= limit:
2162 break
2164 break
2163 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2165 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2164 if opts.get('no_merges') and len(parents) == 2:
2166 if opts.get('no_merges') and len(parents) == 2:
2165 continue
2167 continue
2166 count += 1
2168 count += 1
2167 displayer.show(repo[n])
2169 displayer.show(repo[n])
2168
2170
2169 def parents(ui, repo, file_=None, **opts):
2171 def parents(ui, repo, file_=None, **opts):
2170 """show the parents of the working directory or revision
2172 """show the parents of the working directory or revision
2171
2173
2172 Print the working directory's parent revisions. If a revision is given via
2174 Print the working directory's parent revisions. If a revision is given via
2173 -r/--rev, the parent of that revision will be printed. If a file argument
2175 -r/--rev, the parent of that revision will be printed. If a file argument
2174 is given, the revision in which the file was last changed (before the
2176 is given, the revision in which the file was last changed (before the
2175 working directory revision or the argument to --rev if given) is printed.
2177 working directory revision or the argument to --rev if given) is printed.
2176 """
2178 """
2177 rev = opts.get('rev')
2179 rev = opts.get('rev')
2178 if rev:
2180 if rev:
2179 ctx = repo[rev]
2181 ctx = repo[rev]
2180 else:
2182 else:
2181 ctx = repo[None]
2183 ctx = repo[None]
2182
2184
2183 if file_:
2185 if file_:
2184 m = cmdutil.match(repo, (file_,), opts)
2186 m = cmdutil.match(repo, (file_,), opts)
2185 if m.anypats() or len(m.files()) != 1:
2187 if m.anypats() or len(m.files()) != 1:
2186 raise util.Abort(_('can only specify an explicit filename'))
2188 raise util.Abort(_('can only specify an explicit filename'))
2187 file_ = m.files()[0]
2189 file_ = m.files()[0]
2188 filenodes = []
2190 filenodes = []
2189 for cp in ctx.parents():
2191 for cp in ctx.parents():
2190 if not cp:
2192 if not cp:
2191 continue
2193 continue
2192 try:
2194 try:
2193 filenodes.append(cp.filenode(file_))
2195 filenodes.append(cp.filenode(file_))
2194 except error.LookupError:
2196 except error.LookupError:
2195 pass
2197 pass
2196 if not filenodes:
2198 if not filenodes:
2197 raise util.Abort(_("'%s' not found in manifest!") % file_)
2199 raise util.Abort(_("'%s' not found in manifest!") % file_)
2198 fl = repo.file(file_)
2200 fl = repo.file(file_)
2199 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2201 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2200 else:
2202 else:
2201 p = [cp.node() for cp in ctx.parents()]
2203 p = [cp.node() for cp in ctx.parents()]
2202
2204
2203 displayer = cmdutil.show_changeset(ui, repo, opts)
2205 displayer = cmdutil.show_changeset(ui, repo, opts)
2204 for n in p:
2206 for n in p:
2205 if n != nullid:
2207 if n != nullid:
2206 displayer.show(repo[n])
2208 displayer.show(repo[n])
2207
2209
2208 def paths(ui, repo, search=None):
2210 def paths(ui, repo, search=None):
2209 """show aliases for remote repositories
2211 """show aliases for remote repositories
2210
2212
2211 Show definition of symbolic path name NAME. If no name is given, show
2213 Show definition of symbolic path name NAME. If no name is given, show
2212 definition of all available names.
2214 definition of all available names.
2213
2215
2214 Path names are defined in the [paths] section of /etc/mercurial/hgrc and
2216 Path names are defined in the [paths] section of /etc/mercurial/hgrc and
2215 $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2217 $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2216
2218
2217 See 'hg help urls' for more information.
2219 See 'hg help urls' for more information.
2218 """
2220 """
2219 if search:
2221 if search:
2220 for name, path in ui.configitems("paths"):
2222 for name, path in ui.configitems("paths"):
2221 if name == search:
2223 if name == search:
2222 ui.write("%s\n" % url.hidepassword(path))
2224 ui.write("%s\n" % url.hidepassword(path))
2223 return
2225 return
2224 ui.warn(_("not found!\n"))
2226 ui.warn(_("not found!\n"))
2225 return 1
2227 return 1
2226 else:
2228 else:
2227 for name, path in ui.configitems("paths"):
2229 for name, path in ui.configitems("paths"):
2228 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2230 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2229
2231
2230 def postincoming(ui, repo, modheads, optupdate, checkout):
2232 def postincoming(ui, repo, modheads, optupdate, checkout):
2231 if modheads == 0:
2233 if modheads == 0:
2232 return
2234 return
2233 if optupdate:
2235 if optupdate:
2234 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2236 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2235 return hg.update(repo, checkout)
2237 return hg.update(repo, checkout)
2236 else:
2238 else:
2237 ui.status(_("not updating, since new heads added\n"))
2239 ui.status(_("not updating, since new heads added\n"))
2238 if modheads > 1:
2240 if modheads > 1:
2239 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2241 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2240 else:
2242 else:
2241 ui.status(_("(run 'hg update' to get a working copy)\n"))
2243 ui.status(_("(run 'hg update' to get a working copy)\n"))
2242
2244
2243 def pull(ui, repo, source="default", **opts):
2245 def pull(ui, repo, source="default", **opts):
2244 """pull changes from the specified source
2246 """pull changes from the specified source
2245
2247
2246 Pull changes from a remote repository to a local one.
2248 Pull changes from a remote repository to a local one.
2247
2249
2248 This finds all changes from the repository at the specified path or URL
2250 This finds all changes from the repository at the specified path or URL
2249 and adds them to a local repository (the current one unless -R is
2251 and adds them to a local repository (the current one unless -R is
2250 specified). By default, this does not update the copy of the project in
2252 specified). By default, this does not update the copy of the project in
2251 the working directory.
2253 the working directory.
2252
2254
2253 Use hg incoming if you want to see what would have been added by a pull at
2255 Use hg incoming if you want to see what would have been added by a pull at
2254 the time you issued this command. If you then decide to added those
2256 the time you issued this command. If you then decide to added those
2255 changes to the repository, you should use pull -r X where X is the last
2257 changes to the repository, you should use pull -r X where X is the last
2256 changeset listed by hg incoming.
2258 changeset listed by hg incoming.
2257
2259
2258 If SOURCE is omitted, the 'default' path will be used. See 'hg help urls'
2260 If SOURCE is omitted, the 'default' path will be used. See 'hg help urls'
2259 for more information.
2261 for more information.
2260 """
2262 """
2261 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2263 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2262 other = hg.repository(cmdutil.remoteui(repo, opts), source)
2264 other = hg.repository(cmdutil.remoteui(repo, opts), source)
2263 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2265 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2264 if revs:
2266 if revs:
2265 try:
2267 try:
2266 revs = [other.lookup(rev) for rev in revs]
2268 revs = [other.lookup(rev) for rev in revs]
2267 except error.CapabilityError:
2269 except error.CapabilityError:
2268 err = _("Other repository doesn't support revision lookup, "
2270 err = _("Other repository doesn't support revision lookup, "
2269 "so a rev cannot be specified.")
2271 "so a rev cannot be specified.")
2270 raise util.Abort(err)
2272 raise util.Abort(err)
2271
2273
2272 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2274 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2273 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2275 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2274
2276
2275 def push(ui, repo, dest=None, **opts):
2277 def push(ui, repo, dest=None, **opts):
2276 """push changes to the specified destination
2278 """push changes to the specified destination
2277
2279
2278 Push changes from the local repository to the given destination.
2280 Push changes from the local repository to the given destination.
2279
2281
2280 This is the symmetrical operation for pull. It moves changes from the
2282 This is the symmetrical operation for pull. It moves changes from the
2281 current repository to a different one. If the destination is local this is
2283 current repository to a different one. If the destination is local this is
2282 identical to a pull in that directory from the current one.
2284 identical to a pull in that directory from the current one.
2283
2285
2284 By default, push will refuse to run if it detects the result would
2286 By default, push will refuse to run if it detects the result would
2285 increase the number of remote heads. This generally indicates the user
2287 increase the number of remote heads. This generally indicates the user
2286 forgot to pull and merge before pushing.
2288 forgot to pull and merge before pushing.
2287
2289
2288 If -r/--rev is used, the named revision and all its ancestors will be
2290 If -r/--rev is used, the named revision and all its ancestors will be
2289 pushed to the remote repository.
2291 pushed to the remote repository.
2290
2292
2291 Please see 'hg help urls' for important details about ssh:// URLs. If
2293 Please see 'hg help urls' for important details about ssh:// URLs. If
2292 DESTINATION is omitted, a default path will be used.
2294 DESTINATION is omitted, a default path will be used.
2293 """
2295 """
2294 dest, revs, checkout = hg.parseurl(
2296 dest, revs, checkout = hg.parseurl(
2295 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2297 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2296 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2298 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2297 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2299 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2298 if revs:
2300 if revs:
2299 revs = [repo.lookup(rev) for rev in revs]
2301 revs = [repo.lookup(rev) for rev in revs]
2300
2302
2301 # push subrepos depth-first for coherent ordering
2303 # push subrepos depth-first for coherent ordering
2302 c = repo['']
2304 c = repo['']
2303 subs = c.substate # only repos that are committed
2305 subs = c.substate # only repos that are committed
2304 for s in sorted(subs):
2306 for s in sorted(subs):
2305 c.sub(s).push(opts.get('force'))
2307 c.sub(s).push(opts.get('force'))
2306
2308
2307 r = repo.push(other, opts.get('force'), revs=revs)
2309 r = repo.push(other, opts.get('force'), revs=revs)
2308 return r == 0
2310 return r == 0
2309
2311
2310 def recover(ui, repo):
2312 def recover(ui, repo):
2311 """roll back an interrupted transaction
2313 """roll back an interrupted transaction
2312
2314
2313 Recover from an interrupted commit or pull.
2315 Recover from an interrupted commit or pull.
2314
2316
2315 This command tries to fix the repository status after an interrupted
2317 This command tries to fix the repository status after an interrupted
2316 operation. It should only be necessary when Mercurial suggests it.
2318 operation. It should only be necessary when Mercurial suggests it.
2317 """
2319 """
2318 if repo.recover():
2320 if repo.recover():
2319 return hg.verify(repo)
2321 return hg.verify(repo)
2320 return 1
2322 return 1
2321
2323
2322 def remove(ui, repo, *pats, **opts):
2324 def remove(ui, repo, *pats, **opts):
2323 """remove the specified files on the next commit
2325 """remove the specified files on the next commit
2324
2326
2325 Schedule the indicated files for removal from the repository.
2327 Schedule the indicated files for removal from the repository.
2326
2328
2327 This only removes files from the current branch, not from the entire
2329 This only removes files from the current branch, not from the entire
2328 project history. -A/--after can be used to remove only files that have
2330 project history. -A/--after can be used to remove only files that have
2329 already been deleted, -f/--force can be used to force deletion, and -Af
2331 already been deleted, -f/--force can be used to force deletion, and -Af
2330 can be used to remove files from the next revision without deleting them
2332 can be used to remove files from the next revision without deleting them
2331 from the working directory.
2333 from the working directory.
2332
2334
2333 The following table details the behavior of remove for different file
2335 The following table details the behavior of remove for different file
2334 states (columns) and option combinations (rows). The file states are Added
2336 states (columns) and option combinations (rows). The file states are Added
2335 [A], Clean [C], Modified [M] and Missing [!] (as reported by hg status).
2337 [A], Clean [C], Modified [M] and Missing [!] (as reported by hg status).
2336 The actions are Warn, Remove (from branch) and Delete (from disk)::
2338 The actions are Warn, Remove (from branch) and Delete (from disk)::
2337
2339
2338 A C M !
2340 A C M !
2339 none W RD W R
2341 none W RD W R
2340 -f R RD RD R
2342 -f R RD RD R
2341 -A W W W R
2343 -A W W W R
2342 -Af R R R R
2344 -Af R R R R
2343
2345
2344 This command schedules the files to be removed at the next commit. To undo
2346 This command schedules the files to be removed at the next commit. To undo
2345 a remove before that, see hg revert.
2347 a remove before that, see hg revert.
2346 """
2348 """
2347
2349
2348 after, force = opts.get('after'), opts.get('force')
2350 after, force = opts.get('after'), opts.get('force')
2349 if not pats and not after:
2351 if not pats and not after:
2350 raise util.Abort(_('no files specified'))
2352 raise util.Abort(_('no files specified'))
2351
2353
2352 m = cmdutil.match(repo, pats, opts)
2354 m = cmdutil.match(repo, pats, opts)
2353 s = repo.status(match=m, clean=True)
2355 s = repo.status(match=m, clean=True)
2354 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2356 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2355
2357
2356 for f in m.files():
2358 for f in m.files():
2357 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2359 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2358 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2360 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2359
2361
2360 def warn(files, reason):
2362 def warn(files, reason):
2361 for f in files:
2363 for f in files:
2362 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2364 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2363 % (m.rel(f), reason))
2365 % (m.rel(f), reason))
2364
2366
2365 if force:
2367 if force:
2366 remove, forget = modified + deleted + clean, added
2368 remove, forget = modified + deleted + clean, added
2367 elif after:
2369 elif after:
2368 remove, forget = deleted, []
2370 remove, forget = deleted, []
2369 warn(modified + added + clean, _('still exists'))
2371 warn(modified + added + clean, _('still exists'))
2370 else:
2372 else:
2371 remove, forget = deleted + clean, []
2373 remove, forget = deleted + clean, []
2372 warn(modified, _('is modified'))
2374 warn(modified, _('is modified'))
2373 warn(added, _('has been marked for add'))
2375 warn(added, _('has been marked for add'))
2374
2376
2375 for f in sorted(remove + forget):
2377 for f in sorted(remove + forget):
2376 if ui.verbose or not m.exact(f):
2378 if ui.verbose or not m.exact(f):
2377 ui.status(_('removing %s\n') % m.rel(f))
2379 ui.status(_('removing %s\n') % m.rel(f))
2378
2380
2379 repo.forget(forget)
2381 repo.forget(forget)
2380 repo.remove(remove, unlink=not after)
2382 repo.remove(remove, unlink=not after)
2381
2383
2382 def rename(ui, repo, *pats, **opts):
2384 def rename(ui, repo, *pats, **opts):
2383 """rename files; equivalent of copy + remove
2385 """rename files; equivalent of copy + remove
2384
2386
2385 Mark dest as copies of sources; mark sources for deletion. If dest is a
2387 Mark dest as copies of sources; mark sources for deletion. If dest is a
2386 directory, copies are put in that directory. If dest is a file, there can
2388 directory, copies are put in that directory. If dest is a file, there can
2387 only be one source.
2389 only be one source.
2388
2390
2389 By default, this command copies the contents of files as they exist in the
2391 By default, this command copies the contents of files as they exist in the
2390 working directory. If invoked with -A/--after, the operation is recorded,
2392 working directory. If invoked with -A/--after, the operation is recorded,
2391 but no copying is performed.
2393 but no copying is performed.
2392
2394
2393 This command takes effect at the next commit. To undo a rename before
2395 This command takes effect at the next commit. To undo a rename before
2394 that, see hg revert.
2396 that, see hg revert.
2395 """
2397 """
2396 wlock = repo.wlock(False)
2398 wlock = repo.wlock(False)
2397 try:
2399 try:
2398 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2400 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2399 finally:
2401 finally:
2400 wlock.release()
2402 wlock.release()
2401
2403
2402 def resolve(ui, repo, *pats, **opts):
2404 def resolve(ui, repo, *pats, **opts):
2403 """retry file merges from a merge or update
2405 """retry file merges from a merge or update
2404
2406
2405 This command will cleanly retry unresolved file merges using file
2407 This command will cleanly retry unresolved file merges using file
2406 revisions preserved from the last update or merge. To attempt to resolve
2408 revisions preserved from the last update or merge. To attempt to resolve
2407 all unresolved files, use the -a/--all switch.
2409 all unresolved files, use the -a/--all switch.
2408
2410
2409 If a conflict is resolved manually, please note that the changes will be
2411 If a conflict is resolved manually, please note that the changes will be
2410 overwritten if the merge is retried with resolve. The -m/--mark switch
2412 overwritten if the merge is retried with resolve. The -m/--mark switch
2411 should be used to mark the file as resolved.
2413 should be used to mark the file as resolved.
2412
2414
2413 This command also allows listing resolved files and manually indicating
2415 This command also allows listing resolved files and manually indicating
2414 whether or not files are resolved. All files must be marked as resolved
2416 whether or not files are resolved. All files must be marked as resolved
2415 before a commit is permitted.
2417 before a commit is permitted.
2416
2418
2417 The codes used to show the status of files are::
2419 The codes used to show the status of files are::
2418
2420
2419 U = unresolved
2421 U = unresolved
2420 R = resolved
2422 R = resolved
2421 """
2423 """
2422
2424
2423 all, mark, unmark, show = [opts.get(o) for o in 'all mark unmark list'.split()]
2425 all, mark, unmark, show = [opts.get(o) for o in 'all mark unmark list'.split()]
2424
2426
2425 if (show and (mark or unmark)) or (mark and unmark):
2427 if (show and (mark or unmark)) or (mark and unmark):
2426 raise util.Abort(_("too many options specified"))
2428 raise util.Abort(_("too many options specified"))
2427 if pats and all:
2429 if pats and all:
2428 raise util.Abort(_("can't specify --all and patterns"))
2430 raise util.Abort(_("can't specify --all and patterns"))
2429 if not (all or pats or show or mark or unmark):
2431 if not (all or pats or show or mark or unmark):
2430 raise util.Abort(_('no files or directories specified; '
2432 raise util.Abort(_('no files or directories specified; '
2431 'use --all to remerge all files'))
2433 'use --all to remerge all files'))
2432
2434
2433 ms = merge_.mergestate(repo)
2435 ms = merge_.mergestate(repo)
2434 m = cmdutil.match(repo, pats, opts)
2436 m = cmdutil.match(repo, pats, opts)
2435
2437
2436 for f in ms:
2438 for f in ms:
2437 if m(f):
2439 if m(f):
2438 if show:
2440 if show:
2439 ui.write("%s %s\n" % (ms[f].upper(), f))
2441 ui.write("%s %s\n" % (ms[f].upper(), f))
2440 elif mark:
2442 elif mark:
2441 ms.mark(f, "r")
2443 ms.mark(f, "r")
2442 elif unmark:
2444 elif unmark:
2443 ms.mark(f, "u")
2445 ms.mark(f, "u")
2444 else:
2446 else:
2445 wctx = repo[None]
2447 wctx = repo[None]
2446 mctx = wctx.parents()[-1]
2448 mctx = wctx.parents()[-1]
2447
2449
2448 # backup pre-resolve (merge uses .orig for its own purposes)
2450 # backup pre-resolve (merge uses .orig for its own purposes)
2449 a = repo.wjoin(f)
2451 a = repo.wjoin(f)
2450 util.copyfile(a, a + ".resolve")
2452 util.copyfile(a, a + ".resolve")
2451
2453
2452 # resolve file
2454 # resolve file
2453 ms.resolve(f, wctx, mctx)
2455 ms.resolve(f, wctx, mctx)
2454
2456
2455 # replace filemerge's .orig file with our resolve file
2457 # replace filemerge's .orig file with our resolve file
2456 util.rename(a + ".resolve", a + ".orig")
2458 util.rename(a + ".resolve", a + ".orig")
2457
2459
2458 def revert(ui, repo, *pats, **opts):
2460 def revert(ui, repo, *pats, **opts):
2459 """restore individual files or directories to an earlier state
2461 """restore individual files or directories to an earlier state
2460
2462
2461 (Use update -r to check out earlier revisions, revert does not change the
2463 (Use update -r to check out earlier revisions, revert does not change the
2462 working directory parents.)
2464 working directory parents.)
2463
2465
2464 With no revision specified, revert the named files or directories to the
2466 With no revision specified, revert the named files or directories to the
2465 contents they had in the parent of the working directory. This restores
2467 contents they had in the parent of the working directory. This restores
2466 the contents of the affected files to an unmodified state and unschedules
2468 the contents of the affected files to an unmodified state and unschedules
2467 adds, removes, copies, and renames. If the working directory has two
2469 adds, removes, copies, and renames. If the working directory has two
2468 parents, you must explicitly specify the revision to revert to.
2470 parents, you must explicitly specify the revision to revert to.
2469
2471
2470 Using the -r/--rev option, revert the given files or directories to their
2472 Using the -r/--rev option, revert the given files or directories to their
2471 contents as of a specific revision. This can be helpful to "roll back"
2473 contents as of a specific revision. This can be helpful to "roll back"
2472 some or all of an earlier change. See 'hg help dates' for a list of
2474 some or all of an earlier change. See 'hg help dates' for a list of
2473 formats valid for -d/--date.
2475 formats valid for -d/--date.
2474
2476
2475 Revert modifies the working directory. It does not commit any changes, or
2477 Revert modifies the working directory. It does not commit any changes, or
2476 change the parent of the working directory. If you revert to a revision
2478 change the parent of the working directory. If you revert to a revision
2477 other than the parent of the working directory, the reverted files will
2479 other than the parent of the working directory, the reverted files will
2478 thus appear modified afterwards.
2480 thus appear modified afterwards.
2479
2481
2480 If a file has been deleted, it is restored. If the executable mode of a
2482 If a file has been deleted, it is restored. If the executable mode of a
2481 file was changed, it is reset.
2483 file was changed, it is reset.
2482
2484
2483 If names are given, all files matching the names are reverted. If no
2485 If names are given, all files matching the names are reverted. If no
2484 arguments are given, no files are reverted.
2486 arguments are given, no files are reverted.
2485
2487
2486 Modified files are saved with a .orig suffix before reverting. To disable
2488 Modified files are saved with a .orig suffix before reverting. To disable
2487 these backups, use --no-backup.
2489 these backups, use --no-backup.
2488 """
2490 """
2489
2491
2490 if opts["date"]:
2492 if opts["date"]:
2491 if opts["rev"]:
2493 if opts["rev"]:
2492 raise util.Abort(_("you can't specify a revision and a date"))
2494 raise util.Abort(_("you can't specify a revision and a date"))
2493 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2495 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2494
2496
2495 if not pats and not opts.get('all'):
2497 if not pats and not opts.get('all'):
2496 raise util.Abort(_('no files or directories specified; '
2498 raise util.Abort(_('no files or directories specified; '
2497 'use --all to revert the whole repo'))
2499 'use --all to revert the whole repo'))
2498
2500
2499 parent, p2 = repo.dirstate.parents()
2501 parent, p2 = repo.dirstate.parents()
2500 if not opts.get('rev') and p2 != nullid:
2502 if not opts.get('rev') and p2 != nullid:
2501 raise util.Abort(_('uncommitted merge - please provide a '
2503 raise util.Abort(_('uncommitted merge - please provide a '
2502 'specific revision'))
2504 'specific revision'))
2503 ctx = repo[opts.get('rev')]
2505 ctx = repo[opts.get('rev')]
2504 node = ctx.node()
2506 node = ctx.node()
2505 mf = ctx.manifest()
2507 mf = ctx.manifest()
2506 if node == parent:
2508 if node == parent:
2507 pmf = mf
2509 pmf = mf
2508 else:
2510 else:
2509 pmf = None
2511 pmf = None
2510
2512
2511 # need all matching names in dirstate and manifest of target rev,
2513 # need all matching names in dirstate and manifest of target rev,
2512 # so have to walk both. do not print errors if files exist in one
2514 # so have to walk both. do not print errors if files exist in one
2513 # but not other.
2515 # but not other.
2514
2516
2515 names = {}
2517 names = {}
2516
2518
2517 wlock = repo.wlock()
2519 wlock = repo.wlock()
2518 try:
2520 try:
2519 # walk dirstate.
2521 # walk dirstate.
2520
2522
2521 m = cmdutil.match(repo, pats, opts)
2523 m = cmdutil.match(repo, pats, opts)
2522 m.bad = lambda x,y: False
2524 m.bad = lambda x,y: False
2523 for abs in repo.walk(m):
2525 for abs in repo.walk(m):
2524 names[abs] = m.rel(abs), m.exact(abs)
2526 names[abs] = m.rel(abs), m.exact(abs)
2525
2527
2526 # walk target manifest.
2528 # walk target manifest.
2527
2529
2528 def badfn(path, msg):
2530 def badfn(path, msg):
2529 if path in names:
2531 if path in names:
2530 return
2532 return
2531 path_ = path + '/'
2533 path_ = path + '/'
2532 for f in names:
2534 for f in names:
2533 if f.startswith(path_):
2535 if f.startswith(path_):
2534 return
2536 return
2535 ui.warn("%s: %s\n" % (m.rel(path), msg))
2537 ui.warn("%s: %s\n" % (m.rel(path), msg))
2536
2538
2537 m = cmdutil.match(repo, pats, opts)
2539 m = cmdutil.match(repo, pats, opts)
2538 m.bad = badfn
2540 m.bad = badfn
2539 for abs in repo[node].walk(m):
2541 for abs in repo[node].walk(m):
2540 if abs not in names:
2542 if abs not in names:
2541 names[abs] = m.rel(abs), m.exact(abs)
2543 names[abs] = m.rel(abs), m.exact(abs)
2542
2544
2543 m = cmdutil.matchfiles(repo, names)
2545 m = cmdutil.matchfiles(repo, names)
2544 changes = repo.status(match=m)[:4]
2546 changes = repo.status(match=m)[:4]
2545 modified, added, removed, deleted = map(set, changes)
2547 modified, added, removed, deleted = map(set, changes)
2546
2548
2547 # if f is a rename, also revert the source
2549 # if f is a rename, also revert the source
2548 cwd = repo.getcwd()
2550 cwd = repo.getcwd()
2549 for f in added:
2551 for f in added:
2550 src = repo.dirstate.copied(f)
2552 src = repo.dirstate.copied(f)
2551 if src and src not in names and repo.dirstate[src] == 'r':
2553 if src and src not in names and repo.dirstate[src] == 'r':
2552 removed.add(src)
2554 removed.add(src)
2553 names[src] = (repo.pathto(src, cwd), True)
2555 names[src] = (repo.pathto(src, cwd), True)
2554
2556
2555 def removeforget(abs):
2557 def removeforget(abs):
2556 if repo.dirstate[abs] == 'a':
2558 if repo.dirstate[abs] == 'a':
2557 return _('forgetting %s\n')
2559 return _('forgetting %s\n')
2558 return _('removing %s\n')
2560 return _('removing %s\n')
2559
2561
2560 revert = ([], _('reverting %s\n'))
2562 revert = ([], _('reverting %s\n'))
2561 add = ([], _('adding %s\n'))
2563 add = ([], _('adding %s\n'))
2562 remove = ([], removeforget)
2564 remove = ([], removeforget)
2563 undelete = ([], _('undeleting %s\n'))
2565 undelete = ([], _('undeleting %s\n'))
2564
2566
2565 disptable = (
2567 disptable = (
2566 # dispatch table:
2568 # dispatch table:
2567 # file state
2569 # file state
2568 # action if in target manifest
2570 # action if in target manifest
2569 # action if not in target manifest
2571 # action if not in target manifest
2570 # make backup if in target manifest
2572 # make backup if in target manifest
2571 # make backup if not in target manifest
2573 # make backup if not in target manifest
2572 (modified, revert, remove, True, True),
2574 (modified, revert, remove, True, True),
2573 (added, revert, remove, True, False),
2575 (added, revert, remove, True, False),
2574 (removed, undelete, None, False, False),
2576 (removed, undelete, None, False, False),
2575 (deleted, revert, remove, False, False),
2577 (deleted, revert, remove, False, False),
2576 )
2578 )
2577
2579
2578 for abs, (rel, exact) in sorted(names.items()):
2580 for abs, (rel, exact) in sorted(names.items()):
2579 mfentry = mf.get(abs)
2581 mfentry = mf.get(abs)
2580 target = repo.wjoin(abs)
2582 target = repo.wjoin(abs)
2581 def handle(xlist, dobackup):
2583 def handle(xlist, dobackup):
2582 xlist[0].append(abs)
2584 xlist[0].append(abs)
2583 if dobackup and not opts.get('no_backup') and util.lexists(target):
2585 if dobackup and not opts.get('no_backup') and util.lexists(target):
2584 bakname = "%s.orig" % rel
2586 bakname = "%s.orig" % rel
2585 ui.note(_('saving current version of %s as %s\n') %
2587 ui.note(_('saving current version of %s as %s\n') %
2586 (rel, bakname))
2588 (rel, bakname))
2587 if not opts.get('dry_run'):
2589 if not opts.get('dry_run'):
2588 util.copyfile(target, bakname)
2590 util.copyfile(target, bakname)
2589 if ui.verbose or not exact:
2591 if ui.verbose or not exact:
2590 msg = xlist[1]
2592 msg = xlist[1]
2591 if not isinstance(msg, basestring):
2593 if not isinstance(msg, basestring):
2592 msg = msg(abs)
2594 msg = msg(abs)
2593 ui.status(msg % rel)
2595 ui.status(msg % rel)
2594 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2596 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2595 if abs not in table: continue
2597 if abs not in table: continue
2596 # file has changed in dirstate
2598 # file has changed in dirstate
2597 if mfentry:
2599 if mfentry:
2598 handle(hitlist, backuphit)
2600 handle(hitlist, backuphit)
2599 elif misslist is not None:
2601 elif misslist is not None:
2600 handle(misslist, backupmiss)
2602 handle(misslist, backupmiss)
2601 break
2603 break
2602 else:
2604 else:
2603 if abs not in repo.dirstate:
2605 if abs not in repo.dirstate:
2604 if mfentry:
2606 if mfentry:
2605 handle(add, True)
2607 handle(add, True)
2606 elif exact:
2608 elif exact:
2607 ui.warn(_('file not managed: %s\n') % rel)
2609 ui.warn(_('file not managed: %s\n') % rel)
2608 continue
2610 continue
2609 # file has not changed in dirstate
2611 # file has not changed in dirstate
2610 if node == parent:
2612 if node == parent:
2611 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2613 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2612 continue
2614 continue
2613 if pmf is None:
2615 if pmf is None:
2614 # only need parent manifest in this unlikely case,
2616 # only need parent manifest in this unlikely case,
2615 # so do not read by default
2617 # so do not read by default
2616 pmf = repo[parent].manifest()
2618 pmf = repo[parent].manifest()
2617 if abs in pmf:
2619 if abs in pmf:
2618 if mfentry:
2620 if mfentry:
2619 # if version of file is same in parent and target
2621 # if version of file is same in parent and target
2620 # manifests, do nothing
2622 # manifests, do nothing
2621 if (pmf[abs] != mfentry or
2623 if (pmf[abs] != mfentry or
2622 pmf.flags(abs) != mf.flags(abs)):
2624 pmf.flags(abs) != mf.flags(abs)):
2623 handle(revert, False)
2625 handle(revert, False)
2624 else:
2626 else:
2625 handle(remove, False)
2627 handle(remove, False)
2626
2628
2627 if not opts.get('dry_run'):
2629 if not opts.get('dry_run'):
2628 def checkout(f):
2630 def checkout(f):
2629 fc = ctx[f]
2631 fc = ctx[f]
2630 repo.wwrite(f, fc.data(), fc.flags())
2632 repo.wwrite(f, fc.data(), fc.flags())
2631
2633
2632 audit_path = util.path_auditor(repo.root)
2634 audit_path = util.path_auditor(repo.root)
2633 for f in remove[0]:
2635 for f in remove[0]:
2634 if repo.dirstate[f] == 'a':
2636 if repo.dirstate[f] == 'a':
2635 repo.dirstate.forget(f)
2637 repo.dirstate.forget(f)
2636 continue
2638 continue
2637 audit_path(f)
2639 audit_path(f)
2638 try:
2640 try:
2639 util.unlink(repo.wjoin(f))
2641 util.unlink(repo.wjoin(f))
2640 except OSError:
2642 except OSError:
2641 pass
2643 pass
2642 repo.dirstate.remove(f)
2644 repo.dirstate.remove(f)
2643
2645
2644 normal = None
2646 normal = None
2645 if node == parent:
2647 if node == parent:
2646 # We're reverting to our parent. If possible, we'd like status
2648 # We're reverting to our parent. If possible, we'd like status
2647 # to report the file as clean. We have to use normallookup for
2649 # to report the file as clean. We have to use normallookup for
2648 # merges to avoid losing information about merged/dirty files.
2650 # merges to avoid losing information about merged/dirty files.
2649 if p2 != nullid:
2651 if p2 != nullid:
2650 normal = repo.dirstate.normallookup
2652 normal = repo.dirstate.normallookup
2651 else:
2653 else:
2652 normal = repo.dirstate.normal
2654 normal = repo.dirstate.normal
2653 for f in revert[0]:
2655 for f in revert[0]:
2654 checkout(f)
2656 checkout(f)
2655 if normal:
2657 if normal:
2656 normal(f)
2658 normal(f)
2657
2659
2658 for f in add[0]:
2660 for f in add[0]:
2659 checkout(f)
2661 checkout(f)
2660 repo.dirstate.add(f)
2662 repo.dirstate.add(f)
2661
2663
2662 normal = repo.dirstate.normallookup
2664 normal = repo.dirstate.normallookup
2663 if node == parent and p2 == nullid:
2665 if node == parent and p2 == nullid:
2664 normal = repo.dirstate.normal
2666 normal = repo.dirstate.normal
2665 for f in undelete[0]:
2667 for f in undelete[0]:
2666 checkout(f)
2668 checkout(f)
2667 normal(f)
2669 normal(f)
2668
2670
2669 finally:
2671 finally:
2670 wlock.release()
2672 wlock.release()
2671
2673
2672 def rollback(ui, repo):
2674 def rollback(ui, repo):
2673 """roll back the last transaction
2675 """roll back the last transaction
2674
2676
2675 This command should be used with care. There is only one level of
2677 This command should be used with care. There is only one level of
2676 rollback, and there is no way to undo a rollback. It will also restore the
2678 rollback, and there is no way to undo a rollback. It will also restore the
2677 dirstate at the time of the last transaction, losing any dirstate changes
2679 dirstate at the time of the last transaction, losing any dirstate changes
2678 since that time. This command does not alter the working directory.
2680 since that time. This command does not alter the working directory.
2679
2681
2680 Transactions are used to encapsulate the effects of all commands that
2682 Transactions are used to encapsulate the effects of all commands that
2681 create new changesets or propagate existing changesets into a repository.
2683 create new changesets or propagate existing changesets into a repository.
2682 For example, the following commands are transactional, and their effects
2684 For example, the following commands are transactional, and their effects
2683 can be rolled back::
2685 can be rolled back::
2684
2686
2685 commit
2687 commit
2686 import
2688 import
2687 pull
2689 pull
2688 push (with this repository as destination)
2690 push (with this repository as destination)
2689 unbundle
2691 unbundle
2690
2692
2691 This command is not intended for use on public repositories. Once changes
2693 This command is not intended for use on public repositories. Once changes
2692 are visible for pull by other users, rolling a transaction back locally is
2694 are visible for pull by other users, rolling a transaction back locally is
2693 ineffective (someone else may already have pulled the changes).
2695 ineffective (someone else may already have pulled the changes).
2694 Furthermore, a race is possible with readers of the repository; for
2696 Furthermore, a race is possible with readers of the repository; for
2695 example an in-progress pull from the repository may fail if a rollback is
2697 example an in-progress pull from the repository may fail if a rollback is
2696 performed.
2698 performed.
2697 """
2699 """
2698 repo.rollback()
2700 repo.rollback()
2699
2701
2700 def root(ui, repo):
2702 def root(ui, repo):
2701 """print the root (top) of the current working directory
2703 """print the root (top) of the current working directory
2702
2704
2703 Print the root directory of the current repository.
2705 Print the root directory of the current repository.
2704 """
2706 """
2705 ui.write(repo.root + "\n")
2707 ui.write(repo.root + "\n")
2706
2708
2707 def serve(ui, repo, **opts):
2709 def serve(ui, repo, **opts):
2708 """export the repository via HTTP
2710 """export the repository via HTTP
2709
2711
2710 Start a local HTTP repository browser and pull server.
2712 Start a local HTTP repository browser and pull server.
2711
2713
2712 By default, the server logs accesses to stdout and errors to stderr. Use
2714 By default, the server logs accesses to stdout and errors to stderr. Use
2713 the -A/--accesslog and -E/--errorlog options to log to files.
2715 the -A/--accesslog and -E/--errorlog options to log to files.
2714 """
2716 """
2715
2717
2716 if opts["stdio"]:
2718 if opts["stdio"]:
2717 if repo is None:
2719 if repo is None:
2718 raise error.RepoError(_("There is no Mercurial repository here"
2720 raise error.RepoError(_("There is no Mercurial repository here"
2719 " (.hg not found)"))
2721 " (.hg not found)"))
2720 s = sshserver.sshserver(ui, repo)
2722 s = sshserver.sshserver(ui, repo)
2721 s.serve_forever()
2723 s.serve_forever()
2722
2724
2723 baseui = repo and repo.baseui or ui
2725 baseui = repo and repo.baseui or ui
2724 optlist = ("name templates style address port prefix ipv6"
2726 optlist = ("name templates style address port prefix ipv6"
2725 " accesslog errorlog webdir_conf certificate encoding")
2727 " accesslog errorlog webdir_conf certificate encoding")
2726 for o in optlist.split():
2728 for o in optlist.split():
2727 if opts.get(o, None):
2729 if opts.get(o, None):
2728 baseui.setconfig("web", o, str(opts[o]))
2730 baseui.setconfig("web", o, str(opts[o]))
2729 if (repo is not None) and (repo.ui != baseui):
2731 if (repo is not None) and (repo.ui != baseui):
2730 repo.ui.setconfig("web", o, str(opts[o]))
2732 repo.ui.setconfig("web", o, str(opts[o]))
2731
2733
2732 if repo is None and not ui.config("web", "webdir_conf"):
2734 if repo is None and not ui.config("web", "webdir_conf"):
2733 raise error.RepoError(_("There is no Mercurial repository here"
2735 raise error.RepoError(_("There is no Mercurial repository here"
2734 " (.hg not found)"))
2736 " (.hg not found)"))
2735
2737
2736 class service(object):
2738 class service(object):
2737 def init(self):
2739 def init(self):
2738 util.set_signal_handler()
2740 util.set_signal_handler()
2739 self.httpd = server.create_server(baseui, repo)
2741 self.httpd = server.create_server(baseui, repo)
2740
2742
2741 if not ui.verbose: return
2743 if not ui.verbose: return
2742
2744
2743 if self.httpd.prefix:
2745 if self.httpd.prefix:
2744 prefix = self.httpd.prefix.strip('/') + '/'
2746 prefix = self.httpd.prefix.strip('/') + '/'
2745 else:
2747 else:
2746 prefix = ''
2748 prefix = ''
2747
2749
2748 port = ':%d' % self.httpd.port
2750 port = ':%d' % self.httpd.port
2749 if port == ':80':
2751 if port == ':80':
2750 port = ''
2752 port = ''
2751
2753
2752 bindaddr = self.httpd.addr
2754 bindaddr = self.httpd.addr
2753 if bindaddr == '0.0.0.0':
2755 if bindaddr == '0.0.0.0':
2754 bindaddr = '*'
2756 bindaddr = '*'
2755 elif ':' in bindaddr: # IPv6
2757 elif ':' in bindaddr: # IPv6
2756 bindaddr = '[%s]' % bindaddr
2758 bindaddr = '[%s]' % bindaddr
2757
2759
2758 fqaddr = self.httpd.fqaddr
2760 fqaddr = self.httpd.fqaddr
2759 if ':' in fqaddr:
2761 if ':' in fqaddr:
2760 fqaddr = '[%s]' % fqaddr
2762 fqaddr = '[%s]' % fqaddr
2761 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2763 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2762 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2764 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2763
2765
2764 def run(self):
2766 def run(self):
2765 self.httpd.serve_forever()
2767 self.httpd.serve_forever()
2766
2768
2767 service = service()
2769 service = service()
2768
2770
2769 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2771 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2770
2772
2771 def status(ui, repo, *pats, **opts):
2773 def status(ui, repo, *pats, **opts):
2772 """show changed files in the working directory
2774 """show changed files in the working directory
2773
2775
2774 Show status of files in the repository. If names are given, only files
2776 Show status of files in the repository. If names are given, only files
2775 that match are shown. Files that are clean or ignored or the source of a
2777 that match are shown. Files that are clean or ignored or the source of a
2776 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
2778 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
2777 -C/--copies or -A/--all are given. Unless options described with "show
2779 -C/--copies or -A/--all are given. Unless options described with "show
2778 only ..." are given, the options -mardu are used.
2780 only ..." are given, the options -mardu are used.
2779
2781
2780 Option -q/--quiet hides untracked (unknown and ignored) files unless
2782 Option -q/--quiet hides untracked (unknown and ignored) files unless
2781 explicitly requested with -u/--unknown or -i/--ignored.
2783 explicitly requested with -u/--unknown or -i/--ignored.
2782
2784
2783 NOTE: status may appear to disagree with diff if permissions have changed
2785 NOTE: status may appear to disagree with diff if permissions have changed
2784 or a merge has occurred. The standard diff format does not report
2786 or a merge has occurred. The standard diff format does not report
2785 permission changes and diff only reports changes relative to one merge
2787 permission changes and diff only reports changes relative to one merge
2786 parent.
2788 parent.
2787
2789
2788 If one revision is given, it is used as the base revision. If two
2790 If one revision is given, it is used as the base revision. If two
2789 revisions are given, the differences between them are shown.
2791 revisions are given, the differences between them are shown.
2790
2792
2791 The codes used to show the status of files are::
2793 The codes used to show the status of files are::
2792
2794
2793 M = modified
2795 M = modified
2794 A = added
2796 A = added
2795 R = removed
2797 R = removed
2796 C = clean
2798 C = clean
2797 ! = missing (deleted by non-hg command, but still tracked)
2799 ! = missing (deleted by non-hg command, but still tracked)
2798 ? = not tracked
2800 ? = not tracked
2799 I = ignored
2801 I = ignored
2800 = origin of the previous file listed as A (added)
2802 = origin of the previous file listed as A (added)
2801 """
2803 """
2802
2804
2803 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2805 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2804 cwd = (pats and repo.getcwd()) or ''
2806 cwd = (pats and repo.getcwd()) or ''
2805 end = opts.get('print0') and '\0' or '\n'
2807 end = opts.get('print0') and '\0' or '\n'
2806 copy = {}
2808 copy = {}
2807 states = 'modified added removed deleted unknown ignored clean'.split()
2809 states = 'modified added removed deleted unknown ignored clean'.split()
2808 show = [k for k in states if opts.get(k)]
2810 show = [k for k in states if opts.get(k)]
2809 if opts.get('all'):
2811 if opts.get('all'):
2810 show += ui.quiet and (states[:4] + ['clean']) or states
2812 show += ui.quiet and (states[:4] + ['clean']) or states
2811 if not show:
2813 if not show:
2812 show = ui.quiet and states[:4] or states[:5]
2814 show = ui.quiet and states[:4] or states[:5]
2813
2815
2814 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2816 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2815 'ignored' in show, 'clean' in show, 'unknown' in show)
2817 'ignored' in show, 'clean' in show, 'unknown' in show)
2816 changestates = zip(states, 'MAR!?IC', stat)
2818 changestates = zip(states, 'MAR!?IC', stat)
2817
2819
2818 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2820 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2819 ctxn = repo[nullid]
2821 ctxn = repo[nullid]
2820 ctx1 = repo[node1]
2822 ctx1 = repo[node1]
2821 ctx2 = repo[node2]
2823 ctx2 = repo[node2]
2822 added = stat[1]
2824 added = stat[1]
2823 if node2 is None:
2825 if node2 is None:
2824 added = stat[0] + stat[1] # merged?
2826 added = stat[0] + stat[1] # merged?
2825
2827
2826 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
2828 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
2827 if k in added:
2829 if k in added:
2828 copy[k] = v
2830 copy[k] = v
2829 elif v in added:
2831 elif v in added:
2830 copy[v] = k
2832 copy[v] = k
2831
2833
2832 for state, char, files in changestates:
2834 for state, char, files in changestates:
2833 if state in show:
2835 if state in show:
2834 format = "%s %%s%s" % (char, end)
2836 format = "%s %%s%s" % (char, end)
2835 if opts.get('no_status'):
2837 if opts.get('no_status'):
2836 format = "%%s%s" % end
2838 format = "%%s%s" % end
2837
2839
2838 for f in files:
2840 for f in files:
2839 ui.write(format % repo.pathto(f, cwd))
2841 ui.write(format % repo.pathto(f, cwd))
2840 if f in copy:
2842 if f in copy:
2841 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2843 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2842
2844
2843 def tag(ui, repo, name1, *names, **opts):
2845 def tag(ui, repo, name1, *names, **opts):
2844 """add one or more tags for the current or given revision
2846 """add one or more tags for the current or given revision
2845
2847
2846 Name a particular revision using <name>.
2848 Name a particular revision using <name>.
2847
2849
2848 Tags are used to name particular revisions of the repository and are very
2850 Tags are used to name particular revisions of the repository and are very
2849 useful to compare different revisions, to go back to significant earlier
2851 useful to compare different revisions, to go back to significant earlier
2850 versions or to mark branch points as releases, etc.
2852 versions or to mark branch points as releases, etc.
2851
2853
2852 If no revision is given, the parent of the working directory is used, or
2854 If no revision is given, the parent of the working directory is used, or
2853 tip if no revision is checked out.
2855 tip if no revision is checked out.
2854
2856
2855 To facilitate version control, distribution, and merging of tags, they are
2857 To facilitate version control, distribution, and merging of tags, they are
2856 stored as a file named ".hgtags" which is managed similarly to other
2858 stored as a file named ".hgtags" which is managed similarly to other
2857 project files and can be hand-edited if necessary. The file
2859 project files and can be hand-edited if necessary. The file
2858 '.hg/localtags' is used for local tags (not shared among repositories).
2860 '.hg/localtags' is used for local tags (not shared among repositories).
2859
2861
2860 See 'hg help dates' for a list of formats valid for -d/--date.
2862 See 'hg help dates' for a list of formats valid for -d/--date.
2861 """
2863 """
2862
2864
2863 rev_ = "."
2865 rev_ = "."
2864 names = (name1,) + names
2866 names = (name1,) + names
2865 if len(names) != len(set(names)):
2867 if len(names) != len(set(names)):
2866 raise util.Abort(_('tag names must be unique'))
2868 raise util.Abort(_('tag names must be unique'))
2867 for n in names:
2869 for n in names:
2868 if n in ['tip', '.', 'null']:
2870 if n in ['tip', '.', 'null']:
2869 raise util.Abort(_('the name \'%s\' is reserved') % n)
2871 raise util.Abort(_('the name \'%s\' is reserved') % n)
2870 if opts.get('rev') and opts.get('remove'):
2872 if opts.get('rev') and opts.get('remove'):
2871 raise util.Abort(_("--rev and --remove are incompatible"))
2873 raise util.Abort(_("--rev and --remove are incompatible"))
2872 if opts.get('rev'):
2874 if opts.get('rev'):
2873 rev_ = opts['rev']
2875 rev_ = opts['rev']
2874 message = opts.get('message')
2876 message = opts.get('message')
2875 if opts.get('remove'):
2877 if opts.get('remove'):
2876 expectedtype = opts.get('local') and 'local' or 'global'
2878 expectedtype = opts.get('local') and 'local' or 'global'
2877 for n in names:
2879 for n in names:
2878 if not repo.tagtype(n):
2880 if not repo.tagtype(n):
2879 raise util.Abort(_('tag \'%s\' does not exist') % n)
2881 raise util.Abort(_('tag \'%s\' does not exist') % n)
2880 if repo.tagtype(n) != expectedtype:
2882 if repo.tagtype(n) != expectedtype:
2881 if expectedtype == 'global':
2883 if expectedtype == 'global':
2882 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
2884 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
2883 else:
2885 else:
2884 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
2886 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
2885 rev_ = nullid
2887 rev_ = nullid
2886 if not message:
2888 if not message:
2887 # we don't translate commit messages
2889 # we don't translate commit messages
2888 message = 'Removed tag %s' % ', '.join(names)
2890 message = 'Removed tag %s' % ', '.join(names)
2889 elif not opts.get('force'):
2891 elif not opts.get('force'):
2890 for n in names:
2892 for n in names:
2891 if n in repo.tags():
2893 if n in repo.tags():
2892 raise util.Abort(_('tag \'%s\' already exists '
2894 raise util.Abort(_('tag \'%s\' already exists '
2893 '(use -f to force)') % n)
2895 '(use -f to force)') % n)
2894 if not rev_ and repo.dirstate.parents()[1] != nullid:
2896 if not rev_ and repo.dirstate.parents()[1] != nullid:
2895 raise util.Abort(_('uncommitted merge - please provide a '
2897 raise util.Abort(_('uncommitted merge - please provide a '
2896 'specific revision'))
2898 'specific revision'))
2897 r = repo[rev_].node()
2899 r = repo[rev_].node()
2898
2900
2899 if not message:
2901 if not message:
2900 # we don't translate commit messages
2902 # we don't translate commit messages
2901 message = ('Added tag %s for changeset %s' %
2903 message = ('Added tag %s for changeset %s' %
2902 (', '.join(names), short(r)))
2904 (', '.join(names), short(r)))
2903
2905
2904 date = opts.get('date')
2906 date = opts.get('date')
2905 if date:
2907 if date:
2906 date = util.parsedate(date)
2908 date = util.parsedate(date)
2907
2909
2908 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2910 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2909
2911
2910 def tags(ui, repo):
2912 def tags(ui, repo):
2911 """list repository tags
2913 """list repository tags
2912
2914
2913 This lists both regular and local tags. When the -v/--verbose switch is
2915 This lists both regular and local tags. When the -v/--verbose switch is
2914 used, a third column "local" is printed for local tags.
2916 used, a third column "local" is printed for local tags.
2915 """
2917 """
2916
2918
2917 hexfunc = ui.debugflag and hex or short
2919 hexfunc = ui.debugflag and hex or short
2918 tagtype = ""
2920 tagtype = ""
2919
2921
2920 for t, n in reversed(repo.tagslist()):
2922 for t, n in reversed(repo.tagslist()):
2921 if ui.quiet:
2923 if ui.quiet:
2922 ui.write("%s\n" % t)
2924 ui.write("%s\n" % t)
2923 continue
2925 continue
2924
2926
2925 try:
2927 try:
2926 hn = hexfunc(n)
2928 hn = hexfunc(n)
2927 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2929 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2928 except error.LookupError:
2930 except error.LookupError:
2929 r = " ?:%s" % hn
2931 r = " ?:%s" % hn
2930 else:
2932 else:
2931 spaces = " " * (30 - encoding.colwidth(t))
2933 spaces = " " * (30 - encoding.colwidth(t))
2932 if ui.verbose:
2934 if ui.verbose:
2933 if repo.tagtype(t) == 'local':
2935 if repo.tagtype(t) == 'local':
2934 tagtype = " local"
2936 tagtype = " local"
2935 else:
2937 else:
2936 tagtype = ""
2938 tagtype = ""
2937 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2939 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2938
2940
2939 def tip(ui, repo, **opts):
2941 def tip(ui, repo, **opts):
2940 """show the tip revision
2942 """show the tip revision
2941
2943
2942 The tip revision (usually just called the tip) is the changeset most
2944 The tip revision (usually just called the tip) is the changeset most
2943 recently added to the repository (and therefore the most recently changed
2945 recently added to the repository (and therefore the most recently changed
2944 head).
2946 head).
2945
2947
2946 If you have just made a commit, that commit will be the tip. If you have
2948 If you have just made a commit, that commit will be the tip. If you have
2947 just pulled changes from another repository, the tip of that repository
2949 just pulled changes from another repository, the tip of that repository
2948 becomes the current tip. The "tip" tag is special and cannot be renamed or
2950 becomes the current tip. The "tip" tag is special and cannot be renamed or
2949 assigned to a different changeset.
2951 assigned to a different changeset.
2950 """
2952 """
2951 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
2953 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
2952
2954
2953 def unbundle(ui, repo, fname1, *fnames, **opts):
2955 def unbundle(ui, repo, fname1, *fnames, **opts):
2954 """apply one or more changegroup files
2956 """apply one or more changegroup files
2955
2957
2956 Apply one or more compressed changegroup files generated by the bundle
2958 Apply one or more compressed changegroup files generated by the bundle
2957 command.
2959 command.
2958 """
2960 """
2959 fnames = (fname1,) + fnames
2961 fnames = (fname1,) + fnames
2960
2962
2961 lock = repo.lock()
2963 lock = repo.lock()
2962 try:
2964 try:
2963 for fname in fnames:
2965 for fname in fnames:
2964 f = url.open(ui, fname)
2966 f = url.open(ui, fname)
2965 gen = changegroup.readbundle(f, fname)
2967 gen = changegroup.readbundle(f, fname)
2966 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2968 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2967 finally:
2969 finally:
2968 lock.release()
2970 lock.release()
2969
2971
2970 return postincoming(ui, repo, modheads, opts.get('update'), None)
2972 return postincoming(ui, repo, modheads, opts.get('update'), None)
2971
2973
2972 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
2974 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
2973 """update working directory
2975 """update working directory
2974
2976
2975 Update the repository's working directory to the specified revision, or
2977 Update the repository's working directory to the specified revision, or
2976 the tip of the current branch if none is specified. Use null as the
2978 the tip of the current branch if none is specified. Use null as the
2977 revision to remove the working copy (like 'hg clone -U').
2979 revision to remove the working copy (like 'hg clone -U').
2978
2980
2979 When the working directory contains no uncommitted changes, it will be
2981 When the working directory contains no uncommitted changes, it will be
2980 replaced by the state of the requested revision from the repository. When
2982 replaced by the state of the requested revision from the repository. When
2981 the requested revision is on a different branch, the working directory
2983 the requested revision is on a different branch, the working directory
2982 will additionally be switched to that branch.
2984 will additionally be switched to that branch.
2983
2985
2984 When there are uncommitted changes, use option -C/--clean to discard them,
2986 When there are uncommitted changes, use option -C/--clean to discard them,
2985 forcibly replacing the state of the working directory with the requested
2987 forcibly replacing the state of the working directory with the requested
2986 revision. Alternately, use -c/--check to abort.
2988 revision. Alternately, use -c/--check to abort.
2987
2989
2988 When there are uncommitted changes and option -C/--clean is not used, and
2990 When there are uncommitted changes and option -C/--clean is not used, and
2989 the parent revision and requested revision are on the same branch, and one
2991 the parent revision and requested revision are on the same branch, and one
2990 of them is an ancestor of the other, then the new working directory will
2992 of them is an ancestor of the other, then the new working directory will
2991 contain the requested revision merged with the uncommitted changes.
2993 contain the requested revision merged with the uncommitted changes.
2992 Otherwise, the update will fail with a suggestion to use 'merge' or
2994 Otherwise, the update will fail with a suggestion to use 'merge' or
2993 'update -C' instead.
2995 'update -C' instead.
2994
2996
2995 If you want to update just one file to an older revision, use revert.
2997 If you want to update just one file to an older revision, use revert.
2996
2998
2997 See 'hg help dates' for a list of formats valid for -d/--date.
2999 See 'hg help dates' for a list of formats valid for -d/--date.
2998 """
3000 """
2999 if rev and node:
3001 if rev and node:
3000 raise util.Abort(_("please specify just one revision"))
3002 raise util.Abort(_("please specify just one revision"))
3001
3003
3002 if not rev:
3004 if not rev:
3003 rev = node
3005 rev = node
3004
3006
3005 if not clean and check:
3007 if not clean and check:
3006 # we could use dirty() but we can ignore merge and branch trivia
3008 # we could use dirty() but we can ignore merge and branch trivia
3007 c = repo[None]
3009 c = repo[None]
3008 if c.modified() or c.added() or c.removed():
3010 if c.modified() or c.added() or c.removed():
3009 raise util.Abort(_("uncommitted local changes"))
3011 raise util.Abort(_("uncommitted local changes"))
3010
3012
3011 if date:
3013 if date:
3012 if rev:
3014 if rev:
3013 raise util.Abort(_("you can't specify a revision and a date"))
3015 raise util.Abort(_("you can't specify a revision and a date"))
3014 rev = cmdutil.finddate(ui, repo, date)
3016 rev = cmdutil.finddate(ui, repo, date)
3015
3017
3016 if clean:
3018 if clean or check:
3017 return hg.clean(repo, rev)
3019 return hg.clean(repo, rev)
3018 else:
3020 else:
3019 return hg.update(repo, rev)
3021 return hg.update(repo, rev)
3020
3022
3021 def verify(ui, repo):
3023 def verify(ui, repo):
3022 """verify the integrity of the repository
3024 """verify the integrity of the repository
3023
3025
3024 Verify the integrity of the current repository.
3026 Verify the integrity of the current repository.
3025
3027
3026 This will perform an extensive check of the repository's integrity,
3028 This will perform an extensive check of the repository's integrity,
3027 validating the hashes and checksums of each entry in the changelog,
3029 validating the hashes and checksums of each entry in the changelog,
3028 manifest, and tracked files, as well as the integrity of their crosslinks
3030 manifest, and tracked files, as well as the integrity of their crosslinks
3029 and indices.
3031 and indices.
3030 """
3032 """
3031 return hg.verify(repo)
3033 return hg.verify(repo)
3032
3034
3033 def version_(ui):
3035 def version_(ui):
3034 """output version and copyright information"""
3036 """output version and copyright information"""
3035 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3037 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3036 % util.version())
3038 % util.version())
3037 ui.status(_(
3039 ui.status(_(
3038 "\nCopyright (C) 2005-2009 Matt Mackall <mpm@selenic.com> and others\n"
3040 "\nCopyright (C) 2005-2009 Matt Mackall <mpm@selenic.com> and others\n"
3039 "This is free software; see the source for copying conditions. "
3041 "This is free software; see the source for copying conditions. "
3040 "There is NO\nwarranty; "
3042 "There is NO\nwarranty; "
3041 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3043 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3042 ))
3044 ))
3043
3045
3044 # Command options and aliases are listed here, alphabetically
3046 # Command options and aliases are listed here, alphabetically
3045
3047
3046 globalopts = [
3048 globalopts = [
3047 ('R', 'repository', '',
3049 ('R', 'repository', '',
3048 _('repository root directory or symbolic path name')),
3050 _('repository root directory or symbolic path name')),
3049 ('', 'cwd', '', _('change working directory')),
3051 ('', 'cwd', '', _('change working directory')),
3050 ('y', 'noninteractive', None,
3052 ('y', 'noninteractive', None,
3051 _('do not prompt, assume \'yes\' for any required answers')),
3053 _('do not prompt, assume \'yes\' for any required answers')),
3052 ('q', 'quiet', None, _('suppress output')),
3054 ('q', 'quiet', None, _('suppress output')),
3053 ('v', 'verbose', None, _('enable additional output')),
3055 ('v', 'verbose', None, _('enable additional output')),
3054 ('', 'config', [], _('set/override config option')),
3056 ('', 'config', [], _('set/override config option')),
3055 ('', 'debug', None, _('enable debugging output')),
3057 ('', 'debug', None, _('enable debugging output')),
3056 ('', 'debugger', None, _('start debugger')),
3058 ('', 'debugger', None, _('start debugger')),
3057 ('', 'encoding', encoding.encoding, _('set the charset encoding')),
3059 ('', 'encoding', encoding.encoding, _('set the charset encoding')),
3058 ('', 'encodingmode', encoding.encodingmode,
3060 ('', 'encodingmode', encoding.encodingmode,
3059 _('set the charset encoding mode')),
3061 _('set the charset encoding mode')),
3060 ('', 'traceback', None, _('print traceback on exception')),
3062 ('', 'traceback', None, _('print traceback on exception')),
3061 ('', 'time', None, _('time how long the command takes')),
3063 ('', 'time', None, _('time how long the command takes')),
3062 ('', 'profile', None, _('print command execution profile')),
3064 ('', 'profile', None, _('print command execution profile')),
3063 ('', 'version', None, _('output version information and exit')),
3065 ('', 'version', None, _('output version information and exit')),
3064 ('h', 'help', None, _('display help and exit')),
3066 ('h', 'help', None, _('display help and exit')),
3065 ]
3067 ]
3066
3068
3067 dryrunopts = [('n', 'dry-run', None,
3069 dryrunopts = [('n', 'dry-run', None,
3068 _('do not perform actions, just print output'))]
3070 _('do not perform actions, just print output'))]
3069
3071
3070 remoteopts = [
3072 remoteopts = [
3071 ('e', 'ssh', '', _('specify ssh command to use')),
3073 ('e', 'ssh', '', _('specify ssh command to use')),
3072 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
3074 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
3073 ]
3075 ]
3074
3076
3075 walkopts = [
3077 walkopts = [
3076 ('I', 'include', [], _('include names matching the given patterns')),
3078 ('I', 'include', [], _('include names matching the given patterns')),
3077 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3079 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3078 ]
3080 ]
3079
3081
3080 commitopts = [
3082 commitopts = [
3081 ('m', 'message', '', _('use <text> as commit message')),
3083 ('m', 'message', '', _('use <text> as commit message')),
3082 ('l', 'logfile', '', _('read commit message from <file>')),
3084 ('l', 'logfile', '', _('read commit message from <file>')),
3083 ]
3085 ]
3084
3086
3085 commitopts2 = [
3087 commitopts2 = [
3086 ('d', 'date', '', _('record datecode as commit date')),
3088 ('d', 'date', '', _('record datecode as commit date')),
3087 ('u', 'user', '', _('record the specified user as committer')),
3089 ('u', 'user', '', _('record the specified user as committer')),
3088 ]
3090 ]
3089
3091
3090 templateopts = [
3092 templateopts = [
3091 ('', 'style', '', _('display using template map file')),
3093 ('', 'style', '', _('display using template map file')),
3092 ('', 'template', '', _('display with template')),
3094 ('', 'template', '', _('display with template')),
3093 ]
3095 ]
3094
3096
3095 logopts = [
3097 logopts = [
3096 ('p', 'patch', None, _('show patch')),
3098 ('p', 'patch', None, _('show patch')),
3097 ('g', 'git', None, _('use git extended diff format')),
3099 ('g', 'git', None, _('use git extended diff format')),
3098 ('l', 'limit', '', _('limit number of changes displayed')),
3100 ('l', 'limit', '', _('limit number of changes displayed')),
3099 ('M', 'no-merges', None, _('do not show merges')),
3101 ('M', 'no-merges', None, _('do not show merges')),
3100 ] + templateopts
3102 ] + templateopts
3101
3103
3102 diffopts = [
3104 diffopts = [
3103 ('a', 'text', None, _('treat all files as text')),
3105 ('a', 'text', None, _('treat all files as text')),
3104 ('g', 'git', None, _('use git extended diff format')),
3106 ('g', 'git', None, _('use git extended diff format')),
3105 ('', 'nodates', None, _("don't include dates in diff headers"))
3107 ('', 'nodates', None, _("don't include dates in diff headers"))
3106 ]
3108 ]
3107
3109
3108 diffopts2 = [
3110 diffopts2 = [
3109 ('p', 'show-function', None, _('show which function each change is in')),
3111 ('p', 'show-function', None, _('show which function each change is in')),
3110 ('w', 'ignore-all-space', None,
3112 ('w', 'ignore-all-space', None,
3111 _('ignore white space when comparing lines')),
3113 _('ignore white space when comparing lines')),
3112 ('b', 'ignore-space-change', None,
3114 ('b', 'ignore-space-change', None,
3113 _('ignore changes in the amount of white space')),
3115 _('ignore changes in the amount of white space')),
3114 ('B', 'ignore-blank-lines', None,
3116 ('B', 'ignore-blank-lines', None,
3115 _('ignore changes whose lines are all blank')),
3117 _('ignore changes whose lines are all blank')),
3116 ('U', 'unified', '', _('number of lines of context to show'))
3118 ('U', 'unified', '', _('number of lines of context to show'))
3117 ]
3119 ]
3118
3120
3119 similarityopts = [
3121 similarityopts = [
3120 ('s', 'similarity', '',
3122 ('s', 'similarity', '',
3121 _('guess renamed files by similarity (0<=s<=100)'))
3123 _('guess renamed files by similarity (0<=s<=100)'))
3122 ]
3124 ]
3123
3125
3124 table = {
3126 table = {
3125 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3127 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3126 "addremove":
3128 "addremove":
3127 (addremove, similarityopts + walkopts + dryrunopts,
3129 (addremove, similarityopts + walkopts + dryrunopts,
3128 _('[OPTION]... [FILE]...')),
3130 _('[OPTION]... [FILE]...')),
3129 "^annotate|blame":
3131 "^annotate|blame":
3130 (annotate,
3132 (annotate,
3131 [('r', 'rev', '', _('annotate the specified revision')),
3133 [('r', 'rev', '', _('annotate the specified revision')),
3132 ('f', 'follow', None, _('follow file copies and renames')),
3134 ('f', 'follow', None, _('follow file copies and renames')),
3133 ('a', 'text', None, _('treat all files as text')),
3135 ('a', 'text', None, _('treat all files as text')),
3134 ('u', 'user', None, _('list the author (long with -v)')),
3136 ('u', 'user', None, _('list the author (long with -v)')),
3135 ('d', 'date', None, _('list the date (short with -q)')),
3137 ('d', 'date', None, _('list the date (short with -q)')),
3136 ('n', 'number', None, _('list the revision number (default)')),
3138 ('n', 'number', None, _('list the revision number (default)')),
3137 ('c', 'changeset', None, _('list the changeset')),
3139 ('c', 'changeset', None, _('list the changeset')),
3138 ('l', 'line-number', None,
3140 ('l', 'line-number', None,
3139 _('show line number at the first appearance'))
3141 _('show line number at the first appearance'))
3140 ] + walkopts,
3142 ] + walkopts,
3141 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3143 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3142 "archive":
3144 "archive":
3143 (archive,
3145 (archive,
3144 [('', 'no-decode', None, _('do not pass files through decoders')),
3146 [('', 'no-decode', None, _('do not pass files through decoders')),
3145 ('p', 'prefix', '', _('directory prefix for files in archive')),
3147 ('p', 'prefix', '', _('directory prefix for files in archive')),
3146 ('r', 'rev', '', _('revision to distribute')),
3148 ('r', 'rev', '', _('revision to distribute')),
3147 ('t', 'type', '', _('type of distribution to create')),
3149 ('t', 'type', '', _('type of distribution to create')),
3148 ] + walkopts,
3150 ] + walkopts,
3149 _('[OPTION]... DEST')),
3151 _('[OPTION]... DEST')),
3150 "backout":
3152 "backout":
3151 (backout,
3153 (backout,
3152 [('', 'merge', None,
3154 [('', 'merge', None,
3153 _('merge with old dirstate parent after backout')),
3155 _('merge with old dirstate parent after backout')),
3154 ('', 'parent', '', _('parent to choose when backing out merge')),
3156 ('', 'parent', '', _('parent to choose when backing out merge')),
3155 ('r', 'rev', '', _('revision to backout')),
3157 ('r', 'rev', '', _('revision to backout')),
3156 ] + walkopts + commitopts + commitopts2,
3158 ] + walkopts + commitopts + commitopts2,
3157 _('[OPTION]... [-r] REV')),
3159 _('[OPTION]... [-r] REV')),
3158 "bisect":
3160 "bisect":
3159 (bisect,
3161 (bisect,
3160 [('r', 'reset', False, _('reset bisect state')),
3162 [('r', 'reset', False, _('reset bisect state')),
3161 ('g', 'good', False, _('mark changeset good')),
3163 ('g', 'good', False, _('mark changeset good')),
3162 ('b', 'bad', False, _('mark changeset bad')),
3164 ('b', 'bad', False, _('mark changeset bad')),
3163 ('s', 'skip', False, _('skip testing changeset')),
3165 ('s', 'skip', False, _('skip testing changeset')),
3164 ('c', 'command', '', _('use command to check changeset state')),
3166 ('c', 'command', '', _('use command to check changeset state')),
3165 ('U', 'noupdate', False, _('do not update to target'))],
3167 ('U', 'noupdate', False, _('do not update to target'))],
3166 _("[-gbsr] [-c CMD] [REV]")),
3168 _("[-gbsr] [-c CMD] [REV]")),
3167 "branch":
3169 "branch":
3168 (branch,
3170 (branch,
3169 [('f', 'force', None,
3171 [('f', 'force', None,
3170 _('set branch name even if it shadows an existing branch')),
3172 _('set branch name even if it shadows an existing branch')),
3171 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3173 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3172 _('[-fC] [NAME]')),
3174 _('[-fC] [NAME]')),
3173 "branches":
3175 "branches":
3174 (branches,
3176 (branches,
3175 [('a', 'active', False,
3177 [('a', 'active', False,
3176 _('show only branches that have unmerged heads')),
3178 _('show only branches that have unmerged heads')),
3177 ('c', 'closed', False,
3179 ('c', 'closed', False,
3178 _('show normal and closed heads'))],
3180 _('show normal and closed branches'))],
3179 _('[-a]')),
3181 _('[-a]')),
3180 "bundle":
3182 "bundle":
3181 (bundle,
3183 (bundle,
3182 [('f', 'force', None,
3184 [('f', 'force', None,
3183 _('run even when remote repository is unrelated')),
3185 _('run even when remote repository is unrelated')),
3184 ('r', 'rev', [],
3186 ('r', 'rev', [],
3185 _('a changeset up to which you would like to bundle')),
3187 _('a changeset up to which you would like to bundle')),
3186 ('', 'base', [],
3188 ('', 'base', [],
3187 _('a base changeset to specify instead of a destination')),
3189 _('a base changeset to specify instead of a destination')),
3188 ('a', 'all', None, _('bundle all changesets in the repository')),
3190 ('a', 'all', None, _('bundle all changesets in the repository')),
3189 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3191 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3190 ] + remoteopts,
3192 ] + remoteopts,
3191 _('[-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3193 _('[-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3192 "cat":
3194 "cat":
3193 (cat,
3195 (cat,
3194 [('o', 'output', '', _('print output to file with formatted name')),
3196 [('o', 'output', '', _('print output to file with formatted name')),
3195 ('r', 'rev', '', _('print the given revision')),
3197 ('r', 'rev', '', _('print the given revision')),
3196 ('', 'decode', None, _('apply any matching decode filter')),
3198 ('', 'decode', None, _('apply any matching decode filter')),
3197 ] + walkopts,
3199 ] + walkopts,
3198 _('[OPTION]... FILE...')),
3200 _('[OPTION]... FILE...')),
3199 "^clone":
3201 "^clone":
3200 (clone,
3202 (clone,
3201 [('U', 'noupdate', None,
3203 [('U', 'noupdate', None,
3202 _('the clone will only contain a repository (no working copy)')),
3204 _('the clone will only contain a repository (no working copy)')),
3203 ('r', 'rev', [],
3205 ('r', 'rev', [],
3204 _('a changeset you would like to have after cloning')),
3206 _('a changeset you would like to have after cloning')),
3205 ('', 'pull', None, _('use pull protocol to copy metadata')),
3207 ('', 'pull', None, _('use pull protocol to copy metadata')),
3206 ('', 'uncompressed', None,
3208 ('', 'uncompressed', None,
3207 _('use uncompressed transfer (fast over LAN)')),
3209 _('use uncompressed transfer (fast over LAN)')),
3208 ] + remoteopts,
3210 ] + remoteopts,
3209 _('[OPTION]... SOURCE [DEST]')),
3211 _('[OPTION]... SOURCE [DEST]')),
3210 "^commit|ci":
3212 "^commit|ci":
3211 (commit,
3213 (commit,
3212 [('A', 'addremove', None,
3214 [('A', 'addremove', None,
3213 _('mark new/missing files as added/removed before committing')),
3215 _('mark new/missing files as added/removed before committing')),
3214 ('', 'close-branch', None,
3216 ('', 'close-branch', None,
3215 _('mark a branch as closed, hiding it from the branch list')),
3217 _('mark a branch as closed, hiding it from the branch list')),
3216 ] + walkopts + commitopts + commitopts2,
3218 ] + walkopts + commitopts + commitopts2,
3217 _('[OPTION]... [FILE]...')),
3219 _('[OPTION]... [FILE]...')),
3218 "copy|cp":
3220 "copy|cp":
3219 (copy,
3221 (copy,
3220 [('A', 'after', None, _('record a copy that has already occurred')),
3222 [('A', 'after', None, _('record a copy that has already occurred')),
3221 ('f', 'force', None,
3223 ('f', 'force', None,
3222 _('forcibly copy over an existing managed file')),
3224 _('forcibly copy over an existing managed file')),
3223 ] + walkopts + dryrunopts,
3225 ] + walkopts + dryrunopts,
3224 _('[OPTION]... [SOURCE]... DEST')),
3226 _('[OPTION]... [SOURCE]... DEST')),
3225 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3227 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3226 "debugcheckstate": (debugcheckstate, []),
3228 "debugcheckstate": (debugcheckstate, []),
3227 "debugcommands": (debugcommands, [], _('[COMMAND]')),
3229 "debugcommands": (debugcommands, [], _('[COMMAND]')),
3228 "debugcomplete":
3230 "debugcomplete":
3229 (debugcomplete,
3231 (debugcomplete,
3230 [('o', 'options', None, _('show the command options'))],
3232 [('o', 'options', None, _('show the command options'))],
3231 _('[-o] CMD')),
3233 _('[-o] CMD')),
3232 "debugdate":
3234 "debugdate":
3233 (debugdate,
3235 (debugdate,
3234 [('e', 'extended', None, _('try extended date formats'))],
3236 [('e', 'extended', None, _('try extended date formats'))],
3235 _('[-e] DATE [RANGE]')),
3237 _('[-e] DATE [RANGE]')),
3236 "debugdata": (debugdata, [], _('FILE REV')),
3238 "debugdata": (debugdata, [], _('FILE REV')),
3237 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3239 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3238 "debugindex": (debugindex, [], _('FILE')),
3240 "debugindex": (debugindex, [], _('FILE')),
3239 "debugindexdot": (debugindexdot, [], _('FILE')),
3241 "debugindexdot": (debugindexdot, [], _('FILE')),
3240 "debuginstall": (debuginstall, []),
3242 "debuginstall": (debuginstall, []),
3241 "debugrebuildstate":
3243 "debugrebuildstate":
3242 (debugrebuildstate,
3244 (debugrebuildstate,
3243 [('r', 'rev', '', _('revision to rebuild to'))],
3245 [('r', 'rev', '', _('revision to rebuild to'))],
3244 _('[-r REV] [REV]')),
3246 _('[-r REV] [REV]')),
3245 "debugrename":
3247 "debugrename":
3246 (debugrename,
3248 (debugrename,
3247 [('r', 'rev', '', _('revision to debug'))],
3249 [('r', 'rev', '', _('revision to debug'))],
3248 _('[-r REV] FILE')),
3250 _('[-r REV] FILE')),
3249 "debugsetparents":
3251 "debugsetparents":
3250 (debugsetparents, [], _('REV1 [REV2]')),
3252 (debugsetparents, [], _('REV1 [REV2]')),
3251 "debugstate":
3253 "debugstate":
3252 (debugstate,
3254 (debugstate,
3253 [('', 'nodates', None, _('do not display the saved mtime'))],
3255 [('', 'nodates', None, _('do not display the saved mtime'))],
3254 _('[OPTION]...')),
3256 _('[OPTION]...')),
3255 "debugsub":
3257 "debugsub":
3256 (debugsub,
3258 (debugsub,
3257 [('r', 'rev', '', _('revision to check'))],
3259 [('r', 'rev', '', _('revision to check'))],
3258 _('[-r REV] [REV]')),
3260 _('[-r REV] [REV]')),
3259 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3261 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3260 "^diff":
3262 "^diff":
3261 (diff,
3263 (diff,
3262 [('r', 'rev', [], _('revision')),
3264 [('r', 'rev', [], _('revision')),
3263 ('c', 'change', '', _('change made by revision'))
3265 ('c', 'change', '', _('change made by revision'))
3264 ] + diffopts + diffopts2 + walkopts,
3266 ] + diffopts + diffopts2 + walkopts,
3265 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3267 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3266 "^export":
3268 "^export":
3267 (export,
3269 (export,
3268 [('o', 'output', '', _('print output to file with formatted name')),
3270 [('o', 'output', '', _('print output to file with formatted name')),
3269 ('', 'switch-parent', None, _('diff against the second parent'))
3271 ('', 'switch-parent', None, _('diff against the second parent'))
3270 ] + diffopts,
3272 ] + diffopts,
3271 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3273 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3272 "^forget":
3274 "^forget":
3273 (forget,
3275 (forget,
3274 [] + walkopts,
3276 [] + walkopts,
3275 _('[OPTION]... FILE...')),
3277 _('[OPTION]... FILE...')),
3276 "grep":
3278 "grep":
3277 (grep,
3279 (grep,
3278 [('0', 'print0', None, _('end fields with NUL')),
3280 [('0', 'print0', None, _('end fields with NUL')),
3279 ('', 'all', None, _('print all revisions that match')),
3281 ('', 'all', None, _('print all revisions that match')),
3280 ('f', 'follow', None,
3282 ('f', 'follow', None,
3281 _('follow changeset history, or file history across copies and renames')),
3283 _('follow changeset history, or file history across copies and renames')),
3282 ('i', 'ignore-case', None, _('ignore case when matching')),
3284 ('i', 'ignore-case', None, _('ignore case when matching')),
3283 ('l', 'files-with-matches', None,
3285 ('l', 'files-with-matches', None,
3284 _('print only filenames and revisions that match')),
3286 _('print only filenames and revisions that match')),
3285 ('n', 'line-number', None, _('print matching line numbers')),
3287 ('n', 'line-number', None, _('print matching line numbers')),
3286 ('r', 'rev', [], _('search in given revision range')),
3288 ('r', 'rev', [], _('search in given revision range')),
3287 ('u', 'user', None, _('list the author (long with -v)')),
3289 ('u', 'user', None, _('list the author (long with -v)')),
3288 ('d', 'date', None, _('list the date (short with -q)')),
3290 ('d', 'date', None, _('list the date (short with -q)')),
3289 ] + walkopts,
3291 ] + walkopts,
3290 _('[OPTION]... PATTERN [FILE]...')),
3292 _('[OPTION]... PATTERN [FILE]...')),
3291 "heads":
3293 "heads":
3292 (heads,
3294 (heads,
3293 [('r', 'rev', '', _('show only heads which are descendants of REV')),
3295 [('r', 'rev', '', _('show only heads which are descendants of REV')),
3294 ('a', 'active', False,
3296 ('a', 'active', False,
3295 _('show only the active heads from open branches')),
3297 _('show only the active branch heads from open branches')),
3296 ('c', 'closed', False,
3298 ('c', 'closed', False,
3297 _('show normal and closed heads')),
3299 _('show normal and closed branch heads')),
3298 ] + templateopts,
3300 ] + templateopts,
3299 _('[-r STARTREV] [REV]...')),
3301 _('[-r STARTREV] [REV]...')),
3300 "help": (help_, [], _('[TOPIC]')),
3302 "help": (help_, [], _('[TOPIC]')),
3301 "identify|id":
3303 "identify|id":
3302 (identify,
3304 (identify,
3303 [('r', 'rev', '', _('identify the specified revision')),
3305 [('r', 'rev', '', _('identify the specified revision')),
3304 ('n', 'num', None, _('show local revision number')),
3306 ('n', 'num', None, _('show local revision number')),
3305 ('i', 'id', None, _('show global revision id')),
3307 ('i', 'id', None, _('show global revision id')),
3306 ('b', 'branch', None, _('show branch')),
3308 ('b', 'branch', None, _('show branch')),
3307 ('t', 'tags', None, _('show tags'))],
3309 ('t', 'tags', None, _('show tags'))],
3308 _('[-nibt] [-r REV] [SOURCE]')),
3310 _('[-nibt] [-r REV] [SOURCE]')),
3309 "import|patch":
3311 "import|patch":
3310 (import_,
3312 (import_,
3311 [('p', 'strip', 1,
3313 [('p', 'strip', 1,
3312 _('directory strip option for patch. This has the same '
3314 _('directory strip option for patch. This has the same '
3313 'meaning as the corresponding patch option')),
3315 'meaning as the corresponding patch option')),
3314 ('b', 'base', '', _('base path')),
3316 ('b', 'base', '', _('base path')),
3315 ('f', 'force', None,
3317 ('f', 'force', None,
3316 _('skip check for outstanding uncommitted changes')),
3318 _('skip check for outstanding uncommitted changes')),
3317 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3319 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3318 ('', 'exact', None,
3320 ('', 'exact', None,
3319 _('apply patch to the nodes from which it was generated')),
3321 _('apply patch to the nodes from which it was generated')),
3320 ('', 'import-branch', None,
3322 ('', 'import-branch', None,
3321 _('use any branch information in patch (implied by --exact)'))] +
3323 _('use any branch information in patch (implied by --exact)'))] +
3322 commitopts + commitopts2 + similarityopts,
3324 commitopts + commitopts2 + similarityopts,
3323 _('[OPTION]... PATCH...')),
3325 _('[OPTION]... PATCH...')),
3324 "incoming|in":
3326 "incoming|in":
3325 (incoming,
3327 (incoming,
3326 [('f', 'force', None,
3328 [('f', 'force', None,
3327 _('run even when remote repository is unrelated')),
3329 _('run even when remote repository is unrelated')),
3328 ('n', 'newest-first', None, _('show newest record first')),
3330 ('n', 'newest-first', None, _('show newest record first')),
3329 ('', 'bundle', '', _('file to store the bundles into')),
3331 ('', 'bundle', '', _('file to store the bundles into')),
3330 ('r', 'rev', [],
3332 ('r', 'rev', [],
3331 _('a specific revision up to which you would like to pull')),
3333 _('a specific revision up to which you would like to pull')),
3332 ] + logopts + remoteopts,
3334 ] + logopts + remoteopts,
3333 _('[-p] [-n] [-M] [-f] [-r REV]...'
3335 _('[-p] [-n] [-M] [-f] [-r REV]...'
3334 ' [--bundle FILENAME] [SOURCE]')),
3336 ' [--bundle FILENAME] [SOURCE]')),
3335 "^init":
3337 "^init":
3336 (init,
3338 (init,
3337 remoteopts,
3339 remoteopts,
3338 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3340 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3339 "locate":
3341 "locate":
3340 (locate,
3342 (locate,
3341 [('r', 'rev', '', _('search the repository as it stood at REV')),
3343 [('r', 'rev', '', _('search the repository as it stood at REV')),
3342 ('0', 'print0', None,
3344 ('0', 'print0', None,
3343 _('end filenames with NUL, for use with xargs')),
3345 _('end filenames with NUL, for use with xargs')),
3344 ('f', 'fullpath', None,
3346 ('f', 'fullpath', None,
3345 _('print complete paths from the filesystem root')),
3347 _('print complete paths from the filesystem root')),
3346 ] + walkopts,
3348 ] + walkopts,
3347 _('[OPTION]... [PATTERN]...')),
3349 _('[OPTION]... [PATTERN]...')),
3348 "^log|history":
3350 "^log|history":
3349 (log,
3351 (log,
3350 [('f', 'follow', None,
3352 [('f', 'follow', None,
3351 _('follow changeset history, or file history across copies and renames')),
3353 _('follow changeset history, or file history across copies and renames')),
3352 ('', 'follow-first', None,
3354 ('', 'follow-first', None,
3353 _('only follow the first parent of merge changesets')),
3355 _('only follow the first parent of merge changesets')),
3354 ('d', 'date', '', _('show revisions matching date spec')),
3356 ('d', 'date', '', _('show revisions matching date spec')),
3355 ('C', 'copies', None, _('show copied files')),
3357 ('C', 'copies', None, _('show copied files')),
3356 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3358 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3357 ('r', 'rev', [], _('show the specified revision or range')),
3359 ('r', 'rev', [], _('show the specified revision or range')),
3358 ('', 'removed', None, _('include revisions where files were removed')),
3360 ('', 'removed', None, _('include revisions where files were removed')),
3359 ('m', 'only-merges', None, _('show only merges')),
3361 ('m', 'only-merges', None, _('show only merges')),
3360 ('u', 'user', [], _('revisions committed by user')),
3362 ('u', 'user', [], _('revisions committed by user')),
3361 ('b', 'only-branch', [],
3363 ('b', 'only-branch', [],
3362 _('show only changesets within the given named branch')),
3364 _('show only changesets within the given named branch')),
3363 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3365 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3364 ] + logopts + walkopts,
3366 ] + logopts + walkopts,
3365 _('[OPTION]... [FILE]')),
3367 _('[OPTION]... [FILE]')),
3366 "manifest":
3368 "manifest":
3367 (manifest,
3369 (manifest,
3368 [('r', 'rev', '', _('revision to display'))],
3370 [('r', 'rev', '', _('revision to display'))],
3369 _('[-r REV]')),
3371 _('[-r REV]')),
3370 "^merge":
3372 "^merge":
3371 (merge,
3373 (merge,
3372 [('f', 'force', None, _('force a merge with outstanding changes')),
3374 [('f', 'force', None, _('force a merge with outstanding changes')),
3373 ('r', 'rev', '', _('revision to merge')),
3375 ('r', 'rev', '', _('revision to merge')),
3374 ('P', 'preview', None,
3376 ('P', 'preview', None,
3375 _('review revisions to merge (no merge is performed)'))],
3377 _('review revisions to merge (no merge is performed)'))],
3376 _('[-f] [[-r] REV]')),
3378 _('[-f] [[-r] REV]')),
3377 "outgoing|out":
3379 "outgoing|out":
3378 (outgoing,
3380 (outgoing,
3379 [('f', 'force', None,
3381 [('f', 'force', None,
3380 _('run even when remote repository is unrelated')),
3382 _('run even when remote repository is unrelated')),
3381 ('r', 'rev', [],
3383 ('r', 'rev', [],
3382 _('a specific revision up to which you would like to push')),
3384 _('a specific revision up to which you would like to push')),
3383 ('n', 'newest-first', None, _('show newest record first')),
3385 ('n', 'newest-first', None, _('show newest record first')),
3384 ] + logopts + remoteopts,
3386 ] + logopts + remoteopts,
3385 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3387 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3386 "^parents":
3388 "^parents":
3387 (parents,
3389 (parents,
3388 [('r', 'rev', '', _('show parents from the specified revision')),
3390 [('r', 'rev', '', _('show parents from the specified revision')),
3389 ] + templateopts,
3391 ] + templateopts,
3390 _('[-r REV] [FILE]')),
3392 _('[-r REV] [FILE]')),
3391 "paths": (paths, [], _('[NAME]')),
3393 "paths": (paths, [], _('[NAME]')),
3392 "^pull":
3394 "^pull":
3393 (pull,
3395 (pull,
3394 [('u', 'update', None,
3396 [('u', 'update', None,
3395 _('update to new tip if changesets were pulled')),
3397 _('update to new tip if changesets were pulled')),
3396 ('f', 'force', None,
3398 ('f', 'force', None,
3397 _('run even when remote repository is unrelated')),
3399 _('run even when remote repository is unrelated')),
3398 ('r', 'rev', [],
3400 ('r', 'rev', [],
3399 _('a specific revision up to which you would like to pull')),
3401 _('a specific revision up to which you would like to pull')),
3400 ] + remoteopts,
3402 ] + remoteopts,
3401 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3403 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3402 "^push":
3404 "^push":
3403 (push,
3405 (push,
3404 [('f', 'force', None, _('force push')),
3406 [('f', 'force', None, _('force push')),
3405 ('r', 'rev', [],
3407 ('r', 'rev', [],
3406 _('a specific revision up to which you would like to push')),
3408 _('a specific revision up to which you would like to push')),
3407 ] + remoteopts,
3409 ] + remoteopts,
3408 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3410 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3409 "recover": (recover, []),
3411 "recover": (recover, []),
3410 "^remove|rm":
3412 "^remove|rm":
3411 (remove,
3413 (remove,
3412 [('A', 'after', None, _('record delete for missing files')),
3414 [('A', 'after', None, _('record delete for missing files')),
3413 ('f', 'force', None,
3415 ('f', 'force', None,
3414 _('remove (and delete) file even if added or modified')),
3416 _('remove (and delete) file even if added or modified')),
3415 ] + walkopts,
3417 ] + walkopts,
3416 _('[OPTION]... FILE...')),
3418 _('[OPTION]... FILE...')),
3417 "rename|mv":
3419 "rename|mv":
3418 (rename,
3420 (rename,
3419 [('A', 'after', None, _('record a rename that has already occurred')),
3421 [('A', 'after', None, _('record a rename that has already occurred')),
3420 ('f', 'force', None,
3422 ('f', 'force', None,
3421 _('forcibly copy over an existing managed file')),
3423 _('forcibly copy over an existing managed file')),
3422 ] + walkopts + dryrunopts,
3424 ] + walkopts + dryrunopts,
3423 _('[OPTION]... SOURCE... DEST')),
3425 _('[OPTION]... SOURCE... DEST')),
3424 "resolve":
3426 "resolve":
3425 (resolve,
3427 (resolve,
3426 [('a', 'all', None, _('remerge all unresolved files')),
3428 [('a', 'all', None, _('remerge all unresolved files')),
3427 ('l', 'list', None, _('list state of files needing merge')),
3429 ('l', 'list', None, _('list state of files needing merge')),
3428 ('m', 'mark', None, _('mark files as resolved')),
3430 ('m', 'mark', None, _('mark files as resolved')),
3429 ('u', 'unmark', None, _('unmark files as resolved'))]
3431 ('u', 'unmark', None, _('unmark files as resolved'))]
3430 + walkopts,
3432 + walkopts,
3431 _('[OPTION]... [FILE]...')),
3433 _('[OPTION]... [FILE]...')),
3432 "revert":
3434 "revert":
3433 (revert,
3435 (revert,
3434 [('a', 'all', None, _('revert all changes when no arguments given')),
3436 [('a', 'all', None, _('revert all changes when no arguments given')),
3435 ('d', 'date', '', _('tipmost revision matching date')),
3437 ('d', 'date', '', _('tipmost revision matching date')),
3436 ('r', 'rev', '', _('revision to revert to')),
3438 ('r', 'rev', '', _('revision to revert to')),
3437 ('', 'no-backup', None, _('do not save backup copies of files')),
3439 ('', 'no-backup', None, _('do not save backup copies of files')),
3438 ] + walkopts + dryrunopts,
3440 ] + walkopts + dryrunopts,
3439 _('[OPTION]... [-r REV] [NAME]...')),
3441 _('[OPTION]... [-r REV] [NAME]...')),
3440 "rollback": (rollback, []),
3442 "rollback": (rollback, []),
3441 "root": (root, []),
3443 "root": (root, []),
3442 "^serve":
3444 "^serve":
3443 (serve,
3445 (serve,
3444 [('A', 'accesslog', '', _('name of access log file to write to')),
3446 [('A', 'accesslog', '', _('name of access log file to write to')),
3445 ('d', 'daemon', None, _('run server in background')),
3447 ('d', 'daemon', None, _('run server in background')),
3446 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3448 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3447 ('E', 'errorlog', '', _('name of error log file to write to')),
3449 ('E', 'errorlog', '', _('name of error log file to write to')),
3448 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3450 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3449 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3451 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3450 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3452 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3451 ('n', 'name', '',
3453 ('n', 'name', '',
3452 _('name to show in web pages (default: working directory)')),
3454 _('name to show in web pages (default: working directory)')),
3453 ('', 'webdir-conf', '', _('name of the webdir config file'
3455 ('', 'webdir-conf', '', _('name of the webdir config file'
3454 ' (serve more than one repository)')),
3456 ' (serve more than one repository)')),
3455 ('', 'pid-file', '', _('name of file to write process ID to')),
3457 ('', 'pid-file', '', _('name of file to write process ID to')),
3456 ('', 'stdio', None, _('for remote clients')),
3458 ('', 'stdio', None, _('for remote clients')),
3457 ('t', 'templates', '', _('web templates to use')),
3459 ('t', 'templates', '', _('web templates to use')),
3458 ('', 'style', '', _('template style to use')),
3460 ('', 'style', '', _('template style to use')),
3459 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3461 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3460 ('', 'certificate', '', _('SSL certificate file'))],
3462 ('', 'certificate', '', _('SSL certificate file'))],
3461 _('[OPTION]...')),
3463 _('[OPTION]...')),
3462 "showconfig|debugconfig":
3464 "showconfig|debugconfig":
3463 (showconfig,
3465 (showconfig,
3464 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3466 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3465 _('[-u] [NAME]...')),
3467 _('[-u] [NAME]...')),
3466 "^status|st":
3468 "^status|st":
3467 (status,
3469 (status,
3468 [('A', 'all', None, _('show status of all files')),
3470 [('A', 'all', None, _('show status of all files')),
3469 ('m', 'modified', None, _('show only modified files')),
3471 ('m', 'modified', None, _('show only modified files')),
3470 ('a', 'added', None, _('show only added files')),
3472 ('a', 'added', None, _('show only added files')),
3471 ('r', 'removed', None, _('show only removed files')),
3473 ('r', 'removed', None, _('show only removed files')),
3472 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3474 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3473 ('c', 'clean', None, _('show only files without changes')),
3475 ('c', 'clean', None, _('show only files without changes')),
3474 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3476 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3475 ('i', 'ignored', None, _('show only ignored files')),
3477 ('i', 'ignored', None, _('show only ignored files')),
3476 ('n', 'no-status', None, _('hide status prefix')),
3478 ('n', 'no-status', None, _('hide status prefix')),
3477 ('C', 'copies', None, _('show source of copied files')),
3479 ('C', 'copies', None, _('show source of copied files')),
3478 ('0', 'print0', None,
3480 ('0', 'print0', None,
3479 _('end filenames with NUL, for use with xargs')),
3481 _('end filenames with NUL, for use with xargs')),
3480 ('', 'rev', [], _('show difference from revision')),
3482 ('', 'rev', [], _('show difference from revision')),
3481 ] + walkopts,
3483 ] + walkopts,
3482 _('[OPTION]... [FILE]...')),
3484 _('[OPTION]... [FILE]...')),
3483 "tag":
3485 "tag":
3484 (tag,
3486 (tag,
3485 [('f', 'force', None, _('replace existing tag')),
3487 [('f', 'force', None, _('replace existing tag')),
3486 ('l', 'local', None, _('make the tag local')),
3488 ('l', 'local', None, _('make the tag local')),
3487 ('r', 'rev', '', _('revision to tag')),
3489 ('r', 'rev', '', _('revision to tag')),
3488 ('', 'remove', None, _('remove a tag')),
3490 ('', 'remove', None, _('remove a tag')),
3489 # -l/--local is already there, commitopts cannot be used
3491 # -l/--local is already there, commitopts cannot be used
3490 ('m', 'message', '', _('use <text> as commit message')),
3492 ('m', 'message', '', _('use <text> as commit message')),
3491 ] + commitopts2,
3493 ] + commitopts2,
3492 _('[-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3494 _('[-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3493 "tags": (tags, []),
3495 "tags": (tags, []),
3494 "tip":
3496 "tip":
3495 (tip,
3497 (tip,
3496 [('p', 'patch', None, _('show patch')),
3498 [('p', 'patch', None, _('show patch')),
3497 ('g', 'git', None, _('use git extended diff format')),
3499 ('g', 'git', None, _('use git extended diff format')),
3498 ] + templateopts,
3500 ] + templateopts,
3499 _('[-p]')),
3501 _('[-p]')),
3500 "unbundle":
3502 "unbundle":
3501 (unbundle,
3503 (unbundle,
3502 [('u', 'update', None,
3504 [('u', 'update', None,
3503 _('update to new tip if changesets were unbundled'))],
3505 _('update to new tip if changesets were unbundled'))],
3504 _('[-u] FILE...')),
3506 _('[-u] FILE...')),
3505 "^update|up|checkout|co":
3507 "^update|up|checkout|co":
3506 (update,
3508 (update,
3507 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3509 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3508 ('c', 'check', None, _('check for uncommitted changes')),
3510 ('c', 'check', None, _('check for uncommitted changes')),
3509 ('d', 'date', '', _('tipmost revision matching date')),
3511 ('d', 'date', '', _('tipmost revision matching date')),
3510 ('r', 'rev', '', _('revision'))],
3512 ('r', 'rev', '', _('revision'))],
3511 _('[-C] [-d DATE] [[-r] REV]')),
3513 _('[-C] [-d DATE] [[-r] REV]')),
3512 "verify": (verify, []),
3514 "verify": (verify, []),
3513 "version": (version_, []),
3515 "version": (version_, []),
3514 }
3516 }
3515
3517
3516 norepo = ("clone init version help debugcommands debugcomplete debugdata"
3518 norepo = ("clone init version help debugcommands debugcomplete debugdata"
3517 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3519 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3518 optionalrepo = ("identify paths serve showconfig debugancestor")
3520 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,192 +1,197 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 import errno, os
8 import errno, os
9 from i18n import _
9 from i18n import _
10 import config, util, node, error
10 import config, util, node, error
11 hg = None
11 hg = None
12
12
13 nullstate = ('', '')
13 nullstate = ('', '')
14
14
15 def state(ctx):
15 def state(ctx):
16 p = config.config()
16 p = config.config()
17 def read(f, sections=None, remap=None):
17 def read(f, sections=None, remap=None):
18 if f in ctx:
18 if f in ctx:
19 try:
19 try:
20 p.parse(f, ctx[f].data(), sections, remap)
20 p.parse(f, ctx[f].data(), sections, remap)
21 except IOError, err:
21 except IOError, err:
22 if err.errno != errno.ENOENT:
22 if err.errno != errno.ENOENT:
23 raise
23 raise
24 read('.hgsub')
24 read('.hgsub')
25
25
26 rev = {}
26 rev = {}
27 if '.hgsubstate' in ctx:
27 if '.hgsubstate' in ctx:
28 try:
28 try:
29 for l in ctx['.hgsubstate'].data().splitlines():
29 for l in ctx['.hgsubstate'].data().splitlines():
30 revision, path = l.split()
30 revision, path = l.split()
31 rev[path] = revision
31 rev[path] = revision
32 except IOError, err:
32 except IOError, err:
33 if err.errno != errno.ENOENT:
33 if err.errno != errno.ENOENT:
34 raise
34 raise
35
35
36 state = {}
36 state = {}
37 for path, src in p[''].items():
37 for path, src in p[''].items():
38 state[path] = (src, rev.get(path, ''))
38 state[path] = (src, rev.get(path, ''))
39
39
40 return state
40 return state
41
41
42 def writestate(repo, state):
42 def writestate(repo, state):
43 repo.wwrite('.hgsubstate',
43 repo.wwrite('.hgsubstate',
44 ''.join(['%s %s\n' % (state[s][1], s)
44 ''.join(['%s %s\n' % (state[s][1], s)
45 for s in sorted(state)]), '')
45 for s in sorted(state)]), '')
46
46
47 def submerge(repo, wctx, mctx, actx):
47 def submerge(repo, wctx, mctx, actx):
48 if mctx == actx: # backwards?
48 if mctx == actx: # backwards?
49 actx = wctx.p1()
49 actx = wctx.p1()
50 s1 = wctx.substate
50 s1 = wctx.substate
51 s2 = mctx.substate
51 s2 = mctx.substate
52 sa = actx.substate
52 sa = actx.substate
53 sm = {}
53 sm = {}
54
54
55 for s, l in s1.items():
55 for s, l in s1.items():
56 a = sa.get(s, nullstate)
56 a = sa.get(s, nullstate)
57 if s in s2:
57 if s in s2:
58 r = s2[s]
58 r = s2[s]
59 if l == r or r == a: # no change or local is newer
59 if l == r or r == a: # no change or local is newer
60 sm[s] = l
60 sm[s] = l
61 continue
61 continue
62 elif l == a: # other side changed
62 elif l == a: # other side changed
63 wctx.sub(s).get(r)
63 wctx.sub(s).get(r)
64 sm[s] = r
64 sm[s] = r
65 elif l[0] != r[0]: # sources differ
65 elif l[0] != r[0]: # sources differ
66 if repo.ui.promptchoice(
66 if repo.ui.promptchoice(
67 _(' subrepository sources for %s differ\n'
67 _(' subrepository sources for %s differ\n'
68 'use (l)ocal source (%s) or (r)emote source (%s)?')
68 'use (l)ocal source (%s) or (r)emote source (%s)?')
69 % (s, l[0], r[0]),
69 % (s, l[0], r[0]),
70 (_('&Local'), _('&Remote')), 0):
70 (_('&Local'), _('&Remote')), 0):
71 wctx.sub(s).get(r)
71 wctx.sub(s).get(r)
72 sm[s] = r
72 sm[s] = r
73 elif l[1] == a[1]: # local side is unchanged
73 elif l[1] == a[1]: # local side is unchanged
74 wctx.sub(s).get(r)
74 wctx.sub(s).get(r)
75 sm[s] = r
75 sm[s] = r
76 else:
76 else:
77 wctx.sub(s).merge(r)
77 wctx.sub(s).merge(r)
78 sm[s] = l
78 sm[s] = l
79 elif l == a: # remote removed, local unchanged
79 elif l == a: # remote removed, local unchanged
80 wctx.sub(s).remove()
80 wctx.sub(s).remove()
81 else:
81 else:
82 if repo.ui.promptchoice(
82 if repo.ui.promptchoice(
83 _(' local changed subrepository %s which remote removed\n'
83 _(' local changed subrepository %s which remote removed\n'
84 'use (c)hanged version or (d)elete?') % s,
84 'use (c)hanged version or (d)elete?') % s,
85 (_('&Changed'), _('&Delete')), 0):
85 (_('&Changed'), _('&Delete')), 0):
86 wctx.sub(s).remove()
86 wctx.sub(s).remove()
87
87
88 for s, r in s2.items():
88 for s, r in s2.items():
89 if s in s1:
89 if s in s1:
90 continue
90 continue
91 elif s not in sa:
91 elif s not in sa:
92 wctx.sub(s).get(r)
92 wctx.sub(s).get(r)
93 sm[s] = r
93 sm[s] = r
94 elif r != sa[s]:
94 elif r != sa[s]:
95 if repo.ui.promptchoice(
95 if repo.ui.promptchoice(
96 _(' remote changed subrepository %s which local removed\n'
96 _(' remote changed subrepository %s which local removed\n'
97 'use (c)hanged version or (d)elete?') % s,
97 'use (c)hanged version or (d)elete?') % s,
98 (_('&Changed'), _('&Delete')), 0) == 0:
98 (_('&Changed'), _('&Delete')), 0) == 0:
99 wctx.sub(s).get(r)
99 wctx.sub(s).get(r)
100 sm[s] = r
100 sm[s] = r
101
101
102 # record merged .hgsubstate
102 # record merged .hgsubstate
103 writestate(repo, sm)
103 writestate(repo, sm)
104
104
105 def _abssource(repo, push=False):
105 def _abssource(repo, push=False):
106 if hasattr(repo, '_subparent'):
106 if hasattr(repo, '_subparent'):
107 source = repo._subsource
107 source = repo._subsource
108 if source.startswith('/') or '://' in source:
108 if source.startswith('/') or '://' in source:
109 return source
109 return source
110 return os.path.join(_abssource(repo._subparent), repo._subsource)
110 parent = _abssource(repo._subparent)
111 if '://' in parent:
112 if parent[-1] == '/':
113 parent = parent[:-1]
114 return parent + '/' + source
115 return os.path.join(parent, repo._subsource)
111 if push and repo.ui.config('paths', 'default-push'):
116 if push and repo.ui.config('paths', 'default-push'):
112 return repo.ui.config('paths', 'default-push', repo.root)
117 return repo.ui.config('paths', 'default-push', repo.root)
113 return repo.ui.config('paths', 'default', repo.root)
118 return repo.ui.config('paths', 'default', repo.root)
114
119
115 def subrepo(ctx, path):
120 def subrepo(ctx, path):
116 # subrepo inherently violates our import layering rules
121 # subrepo inherently violates our import layering rules
117 # because it wants to make repo objects from deep inside the stack
122 # because it wants to make repo objects from deep inside the stack
118 # so we manually delay the circular imports to not break
123 # so we manually delay the circular imports to not break
119 # scripts that don't use our demand-loading
124 # scripts that don't use our demand-loading
120 global hg
125 global hg
121 import hg as h
126 import hg as h
122 hg = h
127 hg = h
123
128
124 util.path_auditor(ctx._repo.root)(path)
129 util.path_auditor(ctx._repo.root)(path)
125 state = ctx.substate.get(path, nullstate)
130 state = ctx.substate.get(path, nullstate)
126 if state[0].startswith('['): # future expansion
131 if state[0].startswith('['): # future expansion
127 raise error.Abort('unknown subrepo source %s' % state[0])
132 raise error.Abort('unknown subrepo source %s' % state[0])
128 return hgsubrepo(ctx, path, state)
133 return hgsubrepo(ctx, path, state)
129
134
130 class hgsubrepo(object):
135 class hgsubrepo(object):
131 def __init__(self, ctx, path, state):
136 def __init__(self, ctx, path, state):
132 self._path = path
137 self._path = path
133 self._state = state
138 self._state = state
134 r = ctx._repo
139 r = ctx._repo
135 root = r.wjoin(path)
140 root = r.wjoin(path)
136 if os.path.exists(os.path.join(root, '.hg')):
141 if os.path.exists(os.path.join(root, '.hg')):
137 self._repo = hg.repository(r.ui, root)
142 self._repo = hg.repository(r.ui, root)
138 else:
143 else:
139 util.makedirs(root)
144 util.makedirs(root)
140 self._repo = hg.repository(r.ui, root, create=True)
145 self._repo = hg.repository(r.ui, root, create=True)
141 self._repo._subparent = r
146 self._repo._subparent = r
142 self._repo._subsource = state[0]
147 self._repo._subsource = state[0]
143
148
144 def dirty(self):
149 def dirty(self):
145 r = self._state[1]
150 r = self._state[1]
146 if r == '':
151 if r == '':
147 return True
152 return True
148 w = self._repo[None]
153 w = self._repo[None]
149 if w.p1() != self._repo[r]: # version checked out changed
154 if w.p1() != self._repo[r]: # version checked out changed
150 return True
155 return True
151 return w.dirty() # working directory changed
156 return w.dirty() # working directory changed
152
157
153 def commit(self, text, user, date):
158 def commit(self, text, user, date):
154 n = self._repo.commit(text, user, date)
159 n = self._repo.commit(text, user, date)
155 if not n:
160 if not n:
156 return self._repo['.'].hex() # different version checked out
161 return self._repo['.'].hex() # different version checked out
157 return node.hex(n)
162 return node.hex(n)
158
163
159 def remove(self):
164 def remove(self):
160 # we can't fully delete the repository as it may contain
165 # we can't fully delete the repository as it may contain
161 # local-only history
166 # local-only history
162 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
167 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
163 hg.clean(self._repo, node.nullid, False)
168 hg.clean(self._repo, node.nullid, False)
164
169
165 def get(self, state):
170 def get(self, state):
166 source, revision = state
171 source, revision = state
167 try:
172 try:
168 self._repo.lookup(revision)
173 self._repo.lookup(revision)
169 except error.RepoError:
174 except error.RepoError:
170 self._repo._subsource = source
175 self._repo._subsource = source
171 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
176 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
172 srcurl = _abssource(self._repo)
177 srcurl = _abssource(self._repo)
173 other = hg.repository(self._repo.ui, srcurl)
178 other = hg.repository(self._repo.ui, srcurl)
174 self._repo.pull(other)
179 self._repo.pull(other)
175
180
176 hg.clean(self._repo, revision, False)
181 hg.clean(self._repo, revision, False)
177
182
178 def merge(self, state):
183 def merge(self, state):
179 hg.merge(self._repo, state[1], remind=False)
184 hg.merge(self._repo, state[1], remind=False)
180
185
181 def push(self, force):
186 def push(self, force):
182 # push subrepos depth-first for coherent ordering
187 # push subrepos depth-first for coherent ordering
183 c = self._repo['']
188 c = self._repo['']
184 subs = c.substate # only repos that are committed
189 subs = c.substate # only repos that are committed
185 for s in sorted(subs):
190 for s in sorted(subs):
186 c.sub(s).push(force)
191 c.sub(s).push(force)
187
192
188 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
193 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
189 dsturl = _abssource(self._repo, True)
194 dsturl = _abssource(self._repo, True)
190 other = hg.repository(self._repo.ui, dsturl)
195 other = hg.repository(self._repo.ui, dsturl)
191 self._repo.push(other, force)
196 self._repo.push(other, force)
192
197
@@ -1,192 +1,173 b''
1 marked working directory as branch a
1 marked working directory as branch a
2 marked working directory as branch q
2 marked working directory as branch q
3 reset working directory to branch a
3 reset working directory to branch a
4 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
4 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
5 marked working directory as branch b
5 marked working directory as branch b
6 created new head
6 created new head
7 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
7 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
8 marked working directory as branch c
8 marked working directory as branch c
9 marked working directory as branch a branch name much longer than the default justification used by branches
9 marked working directory as branch a branch name much longer than the default justification used by branches
10 a branch name much longer than the default justification used by branches 7:10ff5895aa57
10 a branch name much longer than the default justification used by branches 7:10ff5895aa57
11 b 4:aee39cd168d0
11 b 4:aee39cd168d0
12 c 6:589736a22561 (inactive)
12 c 6:589736a22561 (inactive)
13 a 5:d8cbc61dbaa6 (inactive)
13 a 5:d8cbc61dbaa6 (inactive)
14 default 0:19709c5a4e75 (inactive)
14 default 0:19709c5a4e75 (inactive)
15 -------
15 -------
16 a branch name much longer than the default justification used by branches 7:10ff5895aa57
16 a branch name much longer than the default justification used by branches 7:10ff5895aa57
17 b 4:aee39cd168d0
17 b 4:aee39cd168d0
18 --- Branch a
18 --- Branch a
19 changeset: 5:d8cbc61dbaa6
19 changeset: 5:d8cbc61dbaa6
20 branch: a
20 branch: a
21 parent: 2:881fe2b92ad0
21 parent: 2:881fe2b92ad0
22 user: test
22 user: test
23 date: Thu Jan 01 00:00:04 1970 +0000
23 date: Thu Jan 01 00:00:04 1970 +0000
24 summary: Adding b branch head 2
24 summary: Adding b branch head 2
25
25
26 changeset: 2:881fe2b92ad0
26 changeset: 2:881fe2b92ad0
27 branch: a
27 branch: a
28 user: test
28 user: test
29 date: Thu Jan 01 00:00:02 1970 +0000
29 date: Thu Jan 01 00:00:02 1970 +0000
30 summary: Adding to a branch
30 summary: Adding to a branch
31
31
32 changeset: 1:dd6b440dd85a
32 changeset: 1:dd6b440dd85a
33 branch: a
33 branch: a
34 user: test
34 user: test
35 date: Thu Jan 01 00:00:01 1970 +0000
35 date: Thu Jan 01 00:00:01 1970 +0000
36 summary: Adding a branch
36 summary: Adding a branch
37
37
38 ---- Branch b
38 ---- Branch b
39 changeset: 4:aee39cd168d0
39 changeset: 4:aee39cd168d0
40 branch: b
40 branch: b
41 user: test
41 user: test
42 date: Thu Jan 01 00:00:03 1970 +0000
42 date: Thu Jan 01 00:00:03 1970 +0000
43 summary: Adding b branch head 1
43 summary: Adding b branch head 1
44
44
45 changeset: 3:ac22033332d1
45 changeset: 3:ac22033332d1
46 branch: b
46 branch: b
47 parent: 0:19709c5a4e75
47 parent: 0:19709c5a4e75
48 user: test
48 user: test
49 date: Thu Jan 01 00:00:02 1970 +0000
49 date: Thu Jan 01 00:00:02 1970 +0000
50 summary: Adding b branch
50 summary: Adding b branch
51
51
52 ---- going to test branch closing
52 ---- going to test branch closing
53 a branch name much longer than the default justification used by branches 7:10ff5895aa57
53 a branch name much longer than the default justification used by branches 7:10ff5895aa57
54 b 4:aee39cd168d0
54 b 4:aee39cd168d0
55 c 6:589736a22561 (inactive)
55 c 6:589736a22561 (inactive)
56 a 5:d8cbc61dbaa6 (inactive)
56 a 5:d8cbc61dbaa6 (inactive)
57 default 0:19709c5a4e75 (inactive)
57 default 0:19709c5a4e75 (inactive)
58 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
58 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 created new head
60 created new head
61 b 10:bfbe841b666e
61 b 10:bfbe841b666e
62 a branch name much longer than the default justification used by branches 7:10ff5895aa57
62 a branch name much longer than the default justification used by branches 7:10ff5895aa57
63 c 6:589736a22561 (inactive)
63 c 6:589736a22561 (inactive)
64 a 5:d8cbc61dbaa6 (inactive)
64 a 5:d8cbc61dbaa6 (inactive)
65 default 0:19709c5a4e75 (inactive)
65 default 0:19709c5a4e75 (inactive)
66 changeset: 10:bfbe841b666e
66 abort: you must specify a branch to use --closed
67 branch: b
68 tag: tip
69 user: test
70 date: Thu Jan 01 00:00:09 1970 +0000
71 summary: adding another cset to branch b
72
73 changeset: 8:eebb944467c9
74 branch: b
75 parent: 4:aee39cd168d0
76 user: test
77 date: Thu Jan 01 00:00:07 1970 +0000
78 summary: adding cset to branch b
79
80 changeset: 7:10ff5895aa57
81 branch: a branch name much longer than the default justification used by branches
82 user: test
83 date: Thu Jan 01 00:00:06 1970 +0000
84 summary: Adding d branch
85
86 changeset: 10:bfbe841b666e
67 changeset: 10:bfbe841b666e
87 branch: b
68 branch: b
88 tag: tip
69 tag: tip
89 user: test
70 user: test
90 date: Thu Jan 01 00:00:09 1970 +0000
71 date: Thu Jan 01 00:00:09 1970 +0000
91 summary: adding another cset to branch b
72 summary: adding another cset to branch b
92
73
93 changeset: 8:eebb944467c9
74 changeset: 8:eebb944467c9
94 branch: b
75 branch: b
95 parent: 4:aee39cd168d0
76 parent: 4:aee39cd168d0
96 user: test
77 user: test
97 date: Thu Jan 01 00:00:07 1970 +0000
78 date: Thu Jan 01 00:00:07 1970 +0000
98 summary: adding cset to branch b
79 summary: adding cset to branch b
99
80
100 changeset: 7:10ff5895aa57
81 changeset: 7:10ff5895aa57
101 branch: a branch name much longer than the default justification used by branches
82 branch: a branch name much longer than the default justification used by branches
102 user: test
83 user: test
103 date: Thu Jan 01 00:00:06 1970 +0000
84 date: Thu Jan 01 00:00:06 1970 +0000
104 summary: Adding d branch
85 summary: Adding d branch
105
86
106 b 8:eebb944467c9
87 b 8:eebb944467c9
107 a branch name much longer than the default justification used by branches 7:10ff5895aa57
88 a branch name much longer than the default justification used by branches 7:10ff5895aa57
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 --- b branch should be inactive
90 --- b branch should be inactive
110 a branch name much longer than the default justification used by branches 7:10ff5895aa57
91 a branch name much longer than the default justification used by branches 7:10ff5895aa57
111 c 6:589736a22561 (inactive)
92 c 6:589736a22561 (inactive)
112 a 5:d8cbc61dbaa6 (inactive)
93 a 5:d8cbc61dbaa6 (inactive)
113 default 0:19709c5a4e75 (inactive)
94 default 0:19709c5a4e75 (inactive)
114 a branch name much longer than the default justification used by branches 7:10ff5895aa57
95 a branch name much longer than the default justification used by branches 7:10ff5895aa57
115 b 12:2da6583810df (closed)
96 b 12:2da6583810df (closed)
116 c 6:589736a22561 (inactive)
97 c 6:589736a22561 (inactive)
117 a 5:d8cbc61dbaa6 (inactive)
98 a 5:d8cbc61dbaa6 (inactive)
118 default 0:19709c5a4e75 (inactive)
99 default 0:19709c5a4e75 (inactive)
119 a branch name much longer than the default justification used by branches 7:10ff5895aa57
100 a branch name much longer than the default justification used by branches 7:10ff5895aa57
120 no open branch heads on branch b
101 no open branch heads on branch b
121 changeset: 12:2da6583810df
102 changeset: 12:2da6583810df
122 branch: b
103 branch: b
123 tag: tip
104 tag: tip
124 parent: 8:eebb944467c9
105 parent: 8:eebb944467c9
125 user: test
106 user: test
126 date: Thu Jan 01 00:00:09 1970 +0000
107 date: Thu Jan 01 00:00:09 1970 +0000
127 summary: close this part branch too
108 summary: close this part branch too
128
109
129 changeset: 11:c84627f3c15d
110 changeset: 11:c84627f3c15d
130 branch: b
111 branch: b
131 user: test
112 user: test
132 date: Thu Jan 01 00:00:09 1970 +0000
113 date: Thu Jan 01 00:00:09 1970 +0000
133 summary: prune bad branch
114 summary: prune bad branch
134
115
135 --- branch b is back in action
116 --- branch b is back in action
136 b 13:6ac12926b8c3
117 b 13:6ac12926b8c3
137 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 a branch name much longer than the default justification used by branches 7:10ff5895aa57
138 ---- test heads listings
119 ---- test heads listings
139 changeset: 13:6ac12926b8c3
120 changeset: 13:6ac12926b8c3
140 branch: b
121 branch: b
141 tag: tip
122 tag: tip
142 user: test
123 user: test
143 date: Thu Jan 01 00:00:09 1970 +0000
124 date: Thu Jan 01 00:00:09 1970 +0000
144 summary: reopen branch with a change
125 summary: reopen branch with a change
145
126
146 changeset: 11:c84627f3c15d
127 changeset: 11:c84627f3c15d
147 branch: b
128 branch: b
148 user: test
129 user: test
149 date: Thu Jan 01 00:00:09 1970 +0000
130 date: Thu Jan 01 00:00:09 1970 +0000
150 summary: prune bad branch
131 summary: prune bad branch
151
132
152 changeset: 7:10ff5895aa57
133 changeset: 7:10ff5895aa57
153 branch: a branch name much longer than the default justification used by branches
134 branch: a branch name much longer than the default justification used by branches
154 user: test
135 user: test
155 date: Thu Jan 01 00:00:06 1970 +0000
136 date: Thu Jan 01 00:00:06 1970 +0000
156 summary: Adding d branch
137 summary: Adding d branch
157
138
158 % branch default
139 % branch default
159 changeset: 0:19709c5a4e75
140 changeset: 0:19709c5a4e75
160 user: test
141 user: test
161 date: Thu Jan 01 00:00:00 1970 +0000
142 date: Thu Jan 01 00:00:00 1970 +0000
162 summary: Adding root node
143 summary: Adding root node
163
144
164 % branch a
145 % branch a
165 changeset: 5:d8cbc61dbaa6
146 changeset: 5:d8cbc61dbaa6
166 branch: a
147 branch: a
167 parent: 2:881fe2b92ad0
148 parent: 2:881fe2b92ad0
168 user: test
149 user: test
169 date: Thu Jan 01 00:00:04 1970 +0000
150 date: Thu Jan 01 00:00:04 1970 +0000
170 summary: Adding b branch head 2
151 summary: Adding b branch head 2
171
152
172 % branch b
153 % branch b
173 changeset: 13:6ac12926b8c3
154 changeset: 13:6ac12926b8c3
174 branch: b
155 branch: b
175 tag: tip
156 tag: tip
176 user: test
157 user: test
177 date: Thu Jan 01 00:00:09 1970 +0000
158 date: Thu Jan 01 00:00:09 1970 +0000
178 summary: reopen branch with a change
159 summary: reopen branch with a change
179
160
180 changeset: 13:6ac12926b8c3
161 changeset: 13:6ac12926b8c3
181 branch: b
162 branch: b
182 tag: tip
163 tag: tip
183 user: test
164 user: test
184 date: Thu Jan 01 00:00:09 1970 +0000
165 date: Thu Jan 01 00:00:09 1970 +0000
185 summary: reopen branch with a change
166 summary: reopen branch with a change
186
167
187 changeset: 11:c84627f3c15d
168 changeset: 11:c84627f3c15d
188 branch: b
169 branch: b
189 user: test
170 user: test
190 date: Thu Jan 01 00:00:09 1970 +0000
171 date: Thu Jan 01 00:00:09 1970 +0000
191 summary: prune bad branch
172 summary: prune bad branch
192
173
General Comments 0
You need to be logged in to leave comments. Login now