##// END OF EJS Templates
Merge with stable
Martin Geisler -
r12084:ff7c1118 merge default
parent child Browse files
Show More
@@ -1,127 +1,131 b''
1 ; Script generated by the Inno Setup Script Wizard.
1 ; Script generated by the Inno Setup Script Wizard.
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3
3
4 #ifndef VERSION
4 #ifndef VERSION
5 #define FileHandle
5 #define FileHandle
6 #define FileLine
6 #define FileLine
7 #define VERSION = "unknown"
7 #define VERSION = "unknown"
8 #if FileHandle = FileOpen(SourcePath + "\..\..\mercurial\__version__.py")
8 #if FileHandle = FileOpen(SourcePath + "\..\..\mercurial\__version__.py")
9 #expr FileLine = FileRead(FileHandle)
9 #expr FileLine = FileRead(FileHandle)
10 #expr FileLine = FileRead(FileHandle)
10 #expr FileLine = FileRead(FileHandle)
11 #define VERSION = Copy(FileLine, Pos('"', FileLine)+1, Len(FileLine)-Pos('"', FileLine)-1)
11 #define VERSION = Copy(FileLine, Pos('"', FileLine)+1, Len(FileLine)-Pos('"', FileLine)-1)
12 #endif
12 #endif
13 #if FileHandle
13 #if FileHandle
14 #expr FileClose(FileHandle)
14 #expr FileClose(FileHandle)
15 #endif
15 #endif
16 #pragma message "Detected Version: " + VERSION
16 #pragma message "Detected Version: " + VERSION
17 #endif
17 #endif
18
18
19 [Setup]
19 [Setup]
20 AppCopyright=Copyright 2005-2010 Matt Mackall and others
20 AppCopyright=Copyright 2005-2010 Matt Mackall and others
21 AppName=Mercurial
21 AppName=Mercurial
22 AppVerName=Mercurial {#VERSION}
22 AppVerName=Mercurial {#VERSION}
23 InfoAfterFile=contrib/win32/postinstall.txt
23 InfoAfterFile=contrib/win32/postinstall.txt
24 LicenseFile=COPYING
24 LicenseFile=COPYING
25 ShowLanguageDialog=yes
25 ShowLanguageDialog=yes
26 AppPublisher=Matt Mackall and others
26 AppPublisher=Matt Mackall and others
27 AppPublisherURL=http://mercurial.selenic.com/
27 AppPublisherURL=http://mercurial.selenic.com/
28 AppSupportURL=http://mercurial.selenic.com/
28 AppSupportURL=http://mercurial.selenic.com/
29 AppUpdatesURL=http://mercurial.selenic.com/
29 AppUpdatesURL=http://mercurial.selenic.com/
30 AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}
30 AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}
31 AppContact=mercurial@selenic.com
31 AppContact=mercurial@selenic.com
32 OutputBaseFilename=Mercurial-{#VERSION}
32 OutputBaseFilename=Mercurial-{#VERSION}
33 DefaultDirName={pf}\Mercurial
33 DefaultDirName={pf}\Mercurial
34 SourceDir=..\..
34 SourceDir=..\..
35 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
35 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
36 VersionInfoCopyright=Copyright 2005-2010 Matt Mackall and others
36 VersionInfoCopyright=Copyright 2005-2010 Matt Mackall and others
37 VersionInfoCompany=Matt Mackall and others
37 VersionInfoCompany=Matt Mackall and others
38 InternalCompressLevel=max
38 InternalCompressLevel=max
39 SolidCompression=true
39 SolidCompression=true
40 SetupIconFile=contrib\win32\mercurial.ico
40 SetupIconFile=contrib\win32\mercurial.ico
41 AllowNoIcons=true
41 AllowNoIcons=true
42 DefaultGroupName=Mercurial
42 DefaultGroupName=Mercurial
43 PrivilegesRequired=none
43 PrivilegesRequired=none
44
44
45 [Files]
45 [Files]
46 Source: contrib\mercurial.el; DestDir: {app}/Contrib
46 Source: contrib\mercurial.el; DestDir: {app}/Contrib
47 Source: contrib\vim\*.*; DestDir: {app}/Contrib/Vim
47 Source: contrib\vim\*.*; DestDir: {app}/Contrib/Vim
48 Source: contrib\zsh_completion; DestDir: {app}/Contrib
48 Source: contrib\zsh_completion; DestDir: {app}/Contrib
49 Source: contrib\bash_completion; DestDir: {app}/Contrib
49 Source: contrib\bash_completion; DestDir: {app}/Contrib
50 Source: contrib\tcsh_completion; DestDir: {app}/Contrib
50 Source: contrib\tcsh_completion; DestDir: {app}/Contrib
51 Source: contrib\tcsh_completion_build.sh; DestDir: {app}/Contrib
51 Source: contrib\tcsh_completion_build.sh; DestDir: {app}/Contrib
52 Source: contrib\hgk; DestDir: {app}/Contrib; DestName: hgk.tcl
52 Source: contrib\hgk; DestDir: {app}/Contrib; DestName: hgk.tcl
53 Source: contrib\xml.rnc; DestDir: {app}/Contrib
53 Source: contrib\xml.rnc; DestDir: {app}/Contrib
54 Source: contrib\shrink-revlog.py; DestDir: {app}/Contrib
54 Source: contrib\shrink-revlog.py; DestDir: {app}/Contrib
55 Source: contrib\mercurial.el; DestDir: {app}/Contrib
56 Source: contrib\mq.el; DestDir: {app}/Contrib
57 Source: contrib\hgweb.fcgi; DestDir: {app}/Contrib
58 Source: contrib\hgweb.wsgi; DestDir: {app}/Contrib
55 Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme
59 Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme
56 Source: contrib\mergetools.hgrc; DestDir: {tmp};
60 Source: contrib\mergetools.hgrc; DestDir: {tmp};
57 Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Check: CheckFile; AfterInstall: ConcatenateFiles;
61 Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Check: CheckFile; AfterInstall: ConcatenateFiles;
58 Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt
62 Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt
59 Source: dist\hg.exe; DestDir: {app}; AfterInstall: Touch('{app}\hg.exe.local')
63 Source: dist\hg.exe; DestDir: {app}; AfterInstall: Touch('{app}\hg.exe.local')
60 Source: dist\python*.dll; Destdir: {app}; Flags: skipifsourcedoesntexist
64 Source: dist\python*.dll; Destdir: {app}; Flags: skipifsourcedoesntexist
61 Source: dist\library.zip; DestDir: {app}
65 Source: dist\library.zip; DestDir: {app}
62 Source: dist\mfc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist
66 Source: dist\mfc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist
63 Source: dist\msvc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist
67 Source: dist\msvc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist
64 Source: dist\Microsoft.VC*.CRT.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist
68 Source: dist\Microsoft.VC*.CRT.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist
65 Source: dist\Microsoft.VC*.MFC.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist
69 Source: dist\Microsoft.VC*.MFC.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist
66 Source: dist\w9xpopen.exe; DestDir: {app}
70 Source: dist\w9xpopen.exe; DestDir: {app}
67 Source: dist\add_path.exe; DestDir: {app}
71 Source: dist\add_path.exe; DestDir: {app}
68 Source: doc\*.html; DestDir: {app}\Docs
72 Source: doc\*.html; DestDir: {app}\Docs
69 Source: doc\style.css; DestDir: {app}\Docs
73 Source: doc\style.css; DestDir: {app}\Docs
70 Source: mercurial\help\*.txt; DestDir: {app}\help
74 Source: mercurial\help\*.txt; DestDir: {app}\help
71 Source: mercurial\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs
75 Source: mercurial\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs
72 Source: mercurial\templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs
76 Source: mercurial\templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs
73 Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt
77 Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt
74 Source: COPYING; DestDir: {app}; DestName: Copying.txt
78 Source: COPYING; DestDir: {app}; DestName: Copying.txt
75
79
76 [INI]
80 [INI]
77 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://mercurial.selenic.com/
81 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://mercurial.selenic.com/
78
82
79 [UninstallDelete]
83 [UninstallDelete]
80 Type: files; Name: {app}\Mercurial.url
84 Type: files; Name: {app}\Mercurial.url
81 Type: files; Name: {app}\Contrib\shrink-revlog.pyc
85 Type: files; Name: {app}\Contrib\shrink-revlog.pyc
82
86
83 [Icons]
87 [Icons]
84 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
88 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
85 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
89 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
86 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
90 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
87 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
91 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
88 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
92 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
89
93
90 [Run]
94 [Run]
91 Filename: "{app}\add_path.exe"; Parameters: "{app}"; Flags: postinstall; Description: "Add the installation path to the search path"
95 Filename: "{app}\add_path.exe"; Parameters: "{app}"; Flags: postinstall; Description: "Add the installation path to the search path"
92
96
93 [UninstallRun]
97 [UninstallRun]
94 Filename: "{app}\add_path.exe"; Parameters: "/del {app}"
98 Filename: "{app}\add_path.exe"; Parameters: "/del {app}"
95
99
96 [UninstallDelete]
100 [UninstallDelete]
97 Type: files; Name: "{app}\hg.exe.local"
101 Type: files; Name: "{app}\hg.exe.local"
98 [Code]
102 [Code]
99 var
103 var
100 WriteFile: Boolean;
104 WriteFile: Boolean;
101 CheckDone: Boolean;
105 CheckDone: Boolean;
102
106
103 function CheckFile(): Boolean;
107 function CheckFile(): Boolean;
104 begin
108 begin
105 if not CheckDone then begin
109 if not CheckDone then begin
106 WriteFile := True;
110 WriteFile := True;
107 if FileExists(ExpandConstant(CurrentFileName)) then begin
111 if FileExists(ExpandConstant(CurrentFileName)) then begin
108 WriteFile := MsgBox('' + ExpandConstant(CurrentFileName) + '' #13#13 'The file already exists.' #13#13 'Would you like Setup to overwrite it?', mbConfirmation, MB_YESNO) = idYes;
112 WriteFile := MsgBox('' + ExpandConstant(CurrentFileName) + '' #13#13 'The file already exists.' #13#13 'Would you like Setup to overwrite it?', mbConfirmation, MB_YESNO) = idYes;
109 end;
113 end;
110 CheckDone := True;
114 CheckDone := True;
111 end;
115 end;
112 Result := WriteFile;
116 Result := WriteFile;
113 end;
117 end;
114
118
115 procedure ConcatenateFiles();
119 procedure ConcatenateFiles();
116 var
120 var
117 MergeConfigs: TArrayOfString;
121 MergeConfigs: TArrayOfString;
118 begin
122 begin
119 if LoadStringsFromFile(ExpandConstant('{tmp}\mergetools.hgrc'),MergeConfigs) then begin
123 if LoadStringsFromFile(ExpandConstant('{tmp}\mergetools.hgrc'),MergeConfigs) then begin
120 SaveStringsToFile(ExpandConstant(CurrentFileName),MergeConfigs,True);
124 SaveStringsToFile(ExpandConstant(CurrentFileName),MergeConfigs,True);
121 end;
125 end;
122 end;
126 end;
123
127
124 procedure Touch(fn: String);
128 procedure Touch(fn: String);
125 begin
129 begin
126 SaveStringToFile(ExpandConstant(fn), '', False);
130 SaveStringToFile(ExpandConstant(fn), '', False);
127 end;
131 end;
@@ -1,543 +1,543 b''
1 # Mercurial extension to provide the 'hg bookmark' command
1 # Mercurial extension to provide the 'hg bookmark' command
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.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 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''track a line of development with movable markers
8 '''track a line of development with movable markers
9
9
10 Bookmarks are local movable markers to changesets. Every bookmark
10 Bookmarks are local movable markers to changesets. Every bookmark
11 points to a changeset identified by its hash. If you commit a
11 points to a changeset identified by its hash. If you commit a
12 changeset that is based on a changeset that has a bookmark on it, the
12 changeset that is based on a changeset that has a bookmark on it, the
13 bookmark shifts to the new changeset.
13 bookmark shifts to the new changeset.
14
14
15 It is possible to use bookmark names in every revision lookup (e.g.
15 It is possible to use bookmark names in every revision lookup (e.g.
16 :hg:`merge`, :hg:`update`).
16 :hg:`merge`, :hg:`update`).
17
17
18 By default, when several bookmarks point to the same changeset, they
18 By default, when several bookmarks point to the same changeset, they
19 will all move forward together. It is possible to obtain a more
19 will all move forward together. It is possible to obtain a more
20 git-like experience by adding the following configuration option to
20 git-like experience by adding the following configuration option to
21 your .hgrc::
21 your configuration file::
22
22
23 [bookmarks]
23 [bookmarks]
24 track.current = True
24 track.current = True
25
25
26 This will cause Mercurial to track the bookmark that you are currently
26 This will cause Mercurial to track the bookmark that you are currently
27 using, and only update it. This is similar to git's approach to
27 using, and only update it. This is similar to git's approach to
28 branching.
28 branching.
29 '''
29 '''
30
30
31 from mercurial.i18n import _
31 from mercurial.i18n import _
32 from mercurial.node import nullid, nullrev, hex, short
32 from mercurial.node import nullid, nullrev, hex, short
33 from mercurial import util, commands, repair, extensions, pushkey, hg, url
33 from mercurial import util, commands, repair, extensions, pushkey, hg, url
34 import os
34 import os
35
35
36 def write(repo):
36 def write(repo):
37 '''Write bookmarks
37 '''Write bookmarks
38
38
39 Write the given bookmark => hash dictionary to the .hg/bookmarks file
39 Write the given bookmark => hash dictionary to the .hg/bookmarks file
40 in a format equal to those of localtags.
40 in a format equal to those of localtags.
41
41
42 We also store a backup of the previous state in undo.bookmarks that
42 We also store a backup of the previous state in undo.bookmarks that
43 can be copied back on rollback.
43 can be copied back on rollback.
44 '''
44 '''
45 refs = repo._bookmarks
45 refs = repo._bookmarks
46 if os.path.exists(repo.join('bookmarks')):
46 if os.path.exists(repo.join('bookmarks')):
47 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
47 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
48 if repo._bookmarkcurrent not in refs:
48 if repo._bookmarkcurrent not in refs:
49 setcurrent(repo, None)
49 setcurrent(repo, None)
50 wlock = repo.wlock()
50 wlock = repo.wlock()
51 try:
51 try:
52 file = repo.opener('bookmarks', 'w', atomictemp=True)
52 file = repo.opener('bookmarks', 'w', atomictemp=True)
53 for refspec, node in refs.iteritems():
53 for refspec, node in refs.iteritems():
54 file.write("%s %s\n" % (hex(node), refspec))
54 file.write("%s %s\n" % (hex(node), refspec))
55 file.rename()
55 file.rename()
56
56
57 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
57 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
58 try:
58 try:
59 os.utime(repo.sjoin('00changelog.i'), None)
59 os.utime(repo.sjoin('00changelog.i'), None)
60 except OSError:
60 except OSError:
61 pass
61 pass
62
62
63 finally:
63 finally:
64 wlock.release()
64 wlock.release()
65
65
66 def setcurrent(repo, mark):
66 def setcurrent(repo, mark):
67 '''Set the name of the bookmark that we are currently on
67 '''Set the name of the bookmark that we are currently on
68
68
69 Set the name of the bookmark that we are on (hg update <bookmark>).
69 Set the name of the bookmark that we are on (hg update <bookmark>).
70 The name is recorded in .hg/bookmarks.current
70 The name is recorded in .hg/bookmarks.current
71 '''
71 '''
72 current = repo._bookmarkcurrent
72 current = repo._bookmarkcurrent
73 if current == mark:
73 if current == mark:
74 return
74 return
75
75
76 refs = repo._bookmarks
76 refs = repo._bookmarks
77
77
78 # do not update if we do update to a rev equal to the current bookmark
78 # do not update if we do update to a rev equal to the current bookmark
79 if (mark and mark not in refs and
79 if (mark and mark not in refs and
80 current and refs[current] == repo.changectx('.').node()):
80 current and refs[current] == repo.changectx('.').node()):
81 return
81 return
82 if mark not in refs:
82 if mark not in refs:
83 mark = ''
83 mark = ''
84 wlock = repo.wlock()
84 wlock = repo.wlock()
85 try:
85 try:
86 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
86 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
87 file.write(mark)
87 file.write(mark)
88 file.rename()
88 file.rename()
89 finally:
89 finally:
90 wlock.release()
90 wlock.release()
91 repo._bookmarkcurrent = mark
91 repo._bookmarkcurrent = mark
92
92
93 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
93 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
94 '''track a line of development with movable markers
94 '''track a line of development with movable markers
95
95
96 Bookmarks are pointers to certain commits that move when
96 Bookmarks are pointers to certain commits that move when
97 committing. Bookmarks are local. They can be renamed, copied and
97 committing. Bookmarks are local. They can be renamed, copied and
98 deleted. It is possible to use bookmark names in :hg:`merge` and
98 deleted. It is possible to use bookmark names in :hg:`merge` and
99 :hg:`update` to merge and update respectively to a given bookmark.
99 :hg:`update` to merge and update respectively to a given bookmark.
100
100
101 You can use :hg:`bookmark NAME` to set a bookmark on the working
101 You can use :hg:`bookmark NAME` to set a bookmark on the working
102 directory's parent revision with the given name. If you specify
102 directory's parent revision with the given name. If you specify
103 a revision using -r REV (where REV may be an existing bookmark),
103 a revision using -r REV (where REV may be an existing bookmark),
104 the bookmark is assigned to that revision.
104 the bookmark is assigned to that revision.
105 '''
105 '''
106 hexfn = ui.debugflag and hex or short
106 hexfn = ui.debugflag and hex or short
107 marks = repo._bookmarks
107 marks = repo._bookmarks
108 cur = repo.changectx('.').node()
108 cur = repo.changectx('.').node()
109
109
110 if rename:
110 if rename:
111 if rename not in marks:
111 if rename not in marks:
112 raise util.Abort(_("a bookmark of this name does not exist"))
112 raise util.Abort(_("a bookmark of this name does not exist"))
113 if mark in marks and not force:
113 if mark in marks and not force:
114 raise util.Abort(_("a bookmark of the same name already exists"))
114 raise util.Abort(_("a bookmark of the same name already exists"))
115 if mark is None:
115 if mark is None:
116 raise util.Abort(_("new bookmark name required"))
116 raise util.Abort(_("new bookmark name required"))
117 marks[mark] = marks[rename]
117 marks[mark] = marks[rename]
118 del marks[rename]
118 del marks[rename]
119 if repo._bookmarkcurrent == rename:
119 if repo._bookmarkcurrent == rename:
120 setcurrent(repo, mark)
120 setcurrent(repo, mark)
121 write(repo)
121 write(repo)
122 return
122 return
123
123
124 if delete:
124 if delete:
125 if mark is None:
125 if mark is None:
126 raise util.Abort(_("bookmark name required"))
126 raise util.Abort(_("bookmark name required"))
127 if mark not in marks:
127 if mark not in marks:
128 raise util.Abort(_("a bookmark of this name does not exist"))
128 raise util.Abort(_("a bookmark of this name does not exist"))
129 if mark == repo._bookmarkcurrent:
129 if mark == repo._bookmarkcurrent:
130 setcurrent(repo, None)
130 setcurrent(repo, None)
131 del marks[mark]
131 del marks[mark]
132 write(repo)
132 write(repo)
133 return
133 return
134
134
135 if mark != None:
135 if mark != None:
136 if "\n" in mark:
136 if "\n" in mark:
137 raise util.Abort(_("bookmark name cannot contain newlines"))
137 raise util.Abort(_("bookmark name cannot contain newlines"))
138 mark = mark.strip()
138 mark = mark.strip()
139 if not mark:
139 if not mark:
140 raise util.Abort(_("bookmark names cannot consist entirely of "
140 raise util.Abort(_("bookmark names cannot consist entirely of "
141 "whitespace"))
141 "whitespace"))
142 if mark in marks and not force:
142 if mark in marks and not force:
143 raise util.Abort(_("a bookmark of the same name already exists"))
143 raise util.Abort(_("a bookmark of the same name already exists"))
144 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
144 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
145 and not force):
145 and not force):
146 raise util.Abort(
146 raise util.Abort(
147 _("a bookmark cannot have the name of an existing branch"))
147 _("a bookmark cannot have the name of an existing branch"))
148 if rev:
148 if rev:
149 marks[mark] = repo.lookup(rev)
149 marks[mark] = repo.lookup(rev)
150 else:
150 else:
151 marks[mark] = repo.changectx('.').node()
151 marks[mark] = repo.changectx('.').node()
152 setcurrent(repo, mark)
152 setcurrent(repo, mark)
153 write(repo)
153 write(repo)
154 return
154 return
155
155
156 if mark is None:
156 if mark is None:
157 if rev:
157 if rev:
158 raise util.Abort(_("bookmark name required"))
158 raise util.Abort(_("bookmark name required"))
159 if len(marks) == 0:
159 if len(marks) == 0:
160 ui.status(_("no bookmarks set\n"))
160 ui.status(_("no bookmarks set\n"))
161 else:
161 else:
162 for bmark, n in marks.iteritems():
162 for bmark, n in marks.iteritems():
163 if ui.configbool('bookmarks', 'track.current'):
163 if ui.configbool('bookmarks', 'track.current'):
164 current = repo._bookmarkcurrent
164 current = repo._bookmarkcurrent
165 if bmark == current and n == cur:
165 if bmark == current and n == cur:
166 prefix, label = '*', 'bookmarks.current'
166 prefix, label = '*', 'bookmarks.current'
167 else:
167 else:
168 prefix, label = ' ', ''
168 prefix, label = ' ', ''
169 else:
169 else:
170 if n == cur:
170 if n == cur:
171 prefix, label = '*', 'bookmarks.current'
171 prefix, label = '*', 'bookmarks.current'
172 else:
172 else:
173 prefix, label = ' ', ''
173 prefix, label = ' ', ''
174
174
175 if ui.quiet:
175 if ui.quiet:
176 ui.write("%s\n" % bmark, label=label)
176 ui.write("%s\n" % bmark, label=label)
177 else:
177 else:
178 ui.write(" %s %-25s %d:%s\n" % (
178 ui.write(" %s %-25s %d:%s\n" % (
179 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
179 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
180 label=label)
180 label=label)
181 return
181 return
182
182
183 def _revstostrip(changelog, node):
183 def _revstostrip(changelog, node):
184 srev = changelog.rev(node)
184 srev = changelog.rev(node)
185 tostrip = [srev]
185 tostrip = [srev]
186 saveheads = []
186 saveheads = []
187 for r in xrange(srev, len(changelog)):
187 for r in xrange(srev, len(changelog)):
188 parents = changelog.parentrevs(r)
188 parents = changelog.parentrevs(r)
189 if parents[0] in tostrip or parents[1] in tostrip:
189 if parents[0] in tostrip or parents[1] in tostrip:
190 tostrip.append(r)
190 tostrip.append(r)
191 if parents[1] != nullrev:
191 if parents[1] != nullrev:
192 for p in parents:
192 for p in parents:
193 if p not in tostrip and p > srev:
193 if p not in tostrip and p > srev:
194 saveheads.append(p)
194 saveheads.append(p)
195 return [r for r in tostrip if r not in saveheads]
195 return [r for r in tostrip if r not in saveheads]
196
196
197 def strip(oldstrip, ui, repo, node, backup="all"):
197 def strip(oldstrip, ui, repo, node, backup="all"):
198 """Strip bookmarks if revisions are stripped using
198 """Strip bookmarks if revisions are stripped using
199 the mercurial.strip method. This usually happens during
199 the mercurial.strip method. This usually happens during
200 qpush and qpop"""
200 qpush and qpop"""
201 revisions = _revstostrip(repo.changelog, node)
201 revisions = _revstostrip(repo.changelog, node)
202 marks = repo._bookmarks
202 marks = repo._bookmarks
203 update = []
203 update = []
204 for mark, n in marks.iteritems():
204 for mark, n in marks.iteritems():
205 if repo.changelog.rev(n) in revisions:
205 if repo.changelog.rev(n) in revisions:
206 update.append(mark)
206 update.append(mark)
207 oldstrip(ui, repo, node, backup)
207 oldstrip(ui, repo, node, backup)
208 if len(update) > 0:
208 if len(update) > 0:
209 for m in update:
209 for m in update:
210 marks[m] = repo.changectx('.').node()
210 marks[m] = repo.changectx('.').node()
211 write(repo)
211 write(repo)
212
212
213 def reposetup(ui, repo):
213 def reposetup(ui, repo):
214 if not repo.local():
214 if not repo.local():
215 return
215 return
216
216
217 class bookmark_repo(repo.__class__):
217 class bookmark_repo(repo.__class__):
218
218
219 @util.propertycache
219 @util.propertycache
220 def _bookmarks(self):
220 def _bookmarks(self):
221 '''Parse .hg/bookmarks file and return a dictionary
221 '''Parse .hg/bookmarks file and return a dictionary
222
222
223 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
223 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
224 in the .hg/bookmarks file.
224 in the .hg/bookmarks file.
225 Read the file and return a (name=>nodeid) dictionary
225 Read the file and return a (name=>nodeid) dictionary
226 '''
226 '''
227 try:
227 try:
228 bookmarks = {}
228 bookmarks = {}
229 for line in self.opener('bookmarks'):
229 for line in self.opener('bookmarks'):
230 sha, refspec = line.strip().split(' ', 1)
230 sha, refspec = line.strip().split(' ', 1)
231 bookmarks[refspec] = super(bookmark_repo, self).lookup(sha)
231 bookmarks[refspec] = super(bookmark_repo, self).lookup(sha)
232 except:
232 except:
233 pass
233 pass
234 return bookmarks
234 return bookmarks
235
235
236 @util.propertycache
236 @util.propertycache
237 def _bookmarkcurrent(self):
237 def _bookmarkcurrent(self):
238 '''Get the current bookmark
238 '''Get the current bookmark
239
239
240 If we use gittishsh branches we have a current bookmark that
240 If we use gittishsh branches we have a current bookmark that
241 we are on. This function returns the name of the bookmark. It
241 we are on. This function returns the name of the bookmark. It
242 is stored in .hg/bookmarks.current
242 is stored in .hg/bookmarks.current
243 '''
243 '''
244 mark = None
244 mark = None
245 if os.path.exists(self.join('bookmarks.current')):
245 if os.path.exists(self.join('bookmarks.current')):
246 file = self.opener('bookmarks.current')
246 file = self.opener('bookmarks.current')
247 # No readline() in posixfile_nt, reading everything is cheap
247 # No readline() in posixfile_nt, reading everything is cheap
248 mark = (file.readlines() or [''])[0]
248 mark = (file.readlines() or [''])[0]
249 if mark == '':
249 if mark == '':
250 mark = None
250 mark = None
251 file.close()
251 file.close()
252 return mark
252 return mark
253
253
254 def rollback(self, *args):
254 def rollback(self, *args):
255 if os.path.exists(self.join('undo.bookmarks')):
255 if os.path.exists(self.join('undo.bookmarks')):
256 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
256 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
257 return super(bookmark_repo, self).rollback(*args)
257 return super(bookmark_repo, self).rollback(*args)
258
258
259 def lookup(self, key):
259 def lookup(self, key):
260 if key in self._bookmarks:
260 if key in self._bookmarks:
261 key = self._bookmarks[key]
261 key = self._bookmarks[key]
262 return super(bookmark_repo, self).lookup(key)
262 return super(bookmark_repo, self).lookup(key)
263
263
264 def _bookmarksupdate(self, parents, node):
264 def _bookmarksupdate(self, parents, node):
265 marks = self._bookmarks
265 marks = self._bookmarks
266 update = False
266 update = False
267 if ui.configbool('bookmarks', 'track.current'):
267 if ui.configbool('bookmarks', 'track.current'):
268 mark = self._bookmarkcurrent
268 mark = self._bookmarkcurrent
269 if mark and marks[mark] in parents:
269 if mark and marks[mark] in parents:
270 marks[mark] = node
270 marks[mark] = node
271 update = True
271 update = True
272 else:
272 else:
273 for mark, n in marks.items():
273 for mark, n in marks.items():
274 if n in parents:
274 if n in parents:
275 marks[mark] = node
275 marks[mark] = node
276 update = True
276 update = True
277 if update:
277 if update:
278 write(self)
278 write(self)
279
279
280 def commitctx(self, ctx, error=False):
280 def commitctx(self, ctx, error=False):
281 """Add a revision to the repository and
281 """Add a revision to the repository and
282 move the bookmark"""
282 move the bookmark"""
283 wlock = self.wlock() # do both commit and bookmark with lock held
283 wlock = self.wlock() # do both commit and bookmark with lock held
284 try:
284 try:
285 node = super(bookmark_repo, self).commitctx(ctx, error)
285 node = super(bookmark_repo, self).commitctx(ctx, error)
286 if node is None:
286 if node is None:
287 return None
287 return None
288 parents = self.changelog.parents(node)
288 parents = self.changelog.parents(node)
289 if parents[1] == nullid:
289 if parents[1] == nullid:
290 parents = (parents[0],)
290 parents = (parents[0],)
291
291
292 self._bookmarksupdate(parents, node)
292 self._bookmarksupdate(parents, node)
293 return node
293 return node
294 finally:
294 finally:
295 wlock.release()
295 wlock.release()
296
296
297 def pull(self, remote, heads=None, force=False):
297 def pull(self, remote, heads=None, force=False):
298 result = super(bookmark_repo, self).pull(remote, heads, force)
298 result = super(bookmark_repo, self).pull(remote, heads, force)
299
299
300 self.ui.debug("checking for updated bookmarks\n")
300 self.ui.debug("checking for updated bookmarks\n")
301 rb = remote.listkeys('bookmarks')
301 rb = remote.listkeys('bookmarks')
302 changed = False
302 changed = False
303 for k in rb.keys():
303 for k in rb.keys():
304 if k in self._bookmarks:
304 if k in self._bookmarks:
305 nr, nl = rb[k], self._bookmarks[k]
305 nr, nl = rb[k], self._bookmarks[k]
306 if nr in self:
306 if nr in self:
307 cr = self[nr]
307 cr = self[nr]
308 cl = self[nl]
308 cl = self[nl]
309 if cl.rev() >= cr.rev():
309 if cl.rev() >= cr.rev():
310 continue
310 continue
311 if cr in cl.descendants():
311 if cr in cl.descendants():
312 self._bookmarks[k] = cr.node()
312 self._bookmarks[k] = cr.node()
313 changed = True
313 changed = True
314 self.ui.status(_("updating bookmark %s\n") % k)
314 self.ui.status(_("updating bookmark %s\n") % k)
315 else:
315 else:
316 self.ui.warn(_("not updating divergent"
316 self.ui.warn(_("not updating divergent"
317 " bookmark %s\n") % k)
317 " bookmark %s\n") % k)
318 if changed:
318 if changed:
319 write(repo)
319 write(repo)
320
320
321 return result
321 return result
322
322
323 def push(self, remote, force=False, revs=None, newbranch=False):
323 def push(self, remote, force=False, revs=None, newbranch=False):
324 result = super(bookmark_repo, self).push(remote, force, revs,
324 result = super(bookmark_repo, self).push(remote, force, revs,
325 newbranch)
325 newbranch)
326
326
327 self.ui.debug("checking for updated bookmarks\n")
327 self.ui.debug("checking for updated bookmarks\n")
328 rb = remote.listkeys('bookmarks')
328 rb = remote.listkeys('bookmarks')
329 for k in rb.keys():
329 for k in rb.keys():
330 if k in self._bookmarks:
330 if k in self._bookmarks:
331 nr, nl = rb[k], self._bookmarks[k]
331 nr, nl = rb[k], self._bookmarks[k]
332 if nr in self:
332 if nr in self:
333 cr = self[nr]
333 cr = self[nr]
334 cl = self[nl]
334 cl = self[nl]
335 if cl in cr.descendants():
335 if cl in cr.descendants():
336 r = remote.pushkey('bookmarks', k, nr, nl)
336 r = remote.pushkey('bookmarks', k, nr, nl)
337 if r:
337 if r:
338 self.ui.status(_("updating bookmark %s\n") % k)
338 self.ui.status(_("updating bookmark %s\n") % k)
339 else:
339 else:
340 self.ui.warn(_('updating bookmark %s'
340 self.ui.warn(_('updating bookmark %s'
341 ' failed!\n') % k)
341 ' failed!\n') % k)
342
342
343 return result
343 return result
344
344
345 def addchangegroup(self, *args, **kwargs):
345 def addchangegroup(self, *args, **kwargs):
346 parents = self.dirstate.parents()
346 parents = self.dirstate.parents()
347
347
348 result = super(bookmark_repo, self).addchangegroup(*args, **kwargs)
348 result = super(bookmark_repo, self).addchangegroup(*args, **kwargs)
349 if result > 1:
349 if result > 1:
350 # We have more heads than before
350 # We have more heads than before
351 return result
351 return result
352 node = self.changelog.tip()
352 node = self.changelog.tip()
353
353
354 self._bookmarksupdate(parents, node)
354 self._bookmarksupdate(parents, node)
355 return result
355 return result
356
356
357 def _findtags(self):
357 def _findtags(self):
358 """Merge bookmarks with normal tags"""
358 """Merge bookmarks with normal tags"""
359 (tags, tagtypes) = super(bookmark_repo, self)._findtags()
359 (tags, tagtypes) = super(bookmark_repo, self)._findtags()
360 tags.update(self._bookmarks)
360 tags.update(self._bookmarks)
361 return (tags, tagtypes)
361 return (tags, tagtypes)
362
362
363 if hasattr(repo, 'invalidate'):
363 if hasattr(repo, 'invalidate'):
364 def invalidate(self):
364 def invalidate(self):
365 super(bookmark_repo, self).invalidate()
365 super(bookmark_repo, self).invalidate()
366 for attr in ('_bookmarks', '_bookmarkcurrent'):
366 for attr in ('_bookmarks', '_bookmarkcurrent'):
367 if attr in self.__dict__:
367 if attr in self.__dict__:
368 delattr(self, attr)
368 delattr(self, attr)
369
369
370 repo.__class__ = bookmark_repo
370 repo.__class__ = bookmark_repo
371
371
372 def listbookmarks(repo):
372 def listbookmarks(repo):
373 # We may try to list bookmarks on a repo type that does not
373 # We may try to list bookmarks on a repo type that does not
374 # support it (e.g., statichttprepository).
374 # support it (e.g., statichttprepository).
375 if not hasattr(repo, '_bookmarks'):
375 if not hasattr(repo, '_bookmarks'):
376 return {}
376 return {}
377
377
378 d = {}
378 d = {}
379 for k, v in repo._bookmarks.iteritems():
379 for k, v in repo._bookmarks.iteritems():
380 d[k] = hex(v)
380 d[k] = hex(v)
381 return d
381 return d
382
382
383 def pushbookmark(repo, key, old, new):
383 def pushbookmark(repo, key, old, new):
384 w = repo.wlock()
384 w = repo.wlock()
385 try:
385 try:
386 marks = repo._bookmarks
386 marks = repo._bookmarks
387 if hex(marks.get(key, '')) != old:
387 if hex(marks.get(key, '')) != old:
388 return False
388 return False
389 if new == '':
389 if new == '':
390 del marks[key]
390 del marks[key]
391 else:
391 else:
392 if new not in repo:
392 if new not in repo:
393 return False
393 return False
394 marks[key] = repo[new].node()
394 marks[key] = repo[new].node()
395 write(repo)
395 write(repo)
396 return True
396 return True
397 finally:
397 finally:
398 w.release()
398 w.release()
399
399
400 def pull(oldpull, ui, repo, source="default", **opts):
400 def pull(oldpull, ui, repo, source="default", **opts):
401 # translate bookmark args to rev args for actual pull
401 # translate bookmark args to rev args for actual pull
402 if opts.get('bookmark'):
402 if opts.get('bookmark'):
403 # this is an unpleasant hack as pull will do this internally
403 # this is an unpleasant hack as pull will do this internally
404 source, branches = hg.parseurl(ui.expandpath(source),
404 source, branches = hg.parseurl(ui.expandpath(source),
405 opts.get('branch'))
405 opts.get('branch'))
406 other = hg.repository(hg.remoteui(repo, opts), source)
406 other = hg.repository(hg.remoteui(repo, opts), source)
407 rb = other.listkeys('bookmarks')
407 rb = other.listkeys('bookmarks')
408
408
409 for b in opts['bookmark']:
409 for b in opts['bookmark']:
410 if b not in rb:
410 if b not in rb:
411 raise util.Abort(_('remote bookmark %s not found!') % b)
411 raise util.Abort(_('remote bookmark %s not found!') % b)
412 opts.setdefault('rev', []).append(b)
412 opts.setdefault('rev', []).append(b)
413
413
414 result = oldpull(ui, repo, source, **opts)
414 result = oldpull(ui, repo, source, **opts)
415
415
416 # update specified bookmarks
416 # update specified bookmarks
417 if opts.get('bookmark'):
417 if opts.get('bookmark'):
418 for b in opts['bookmark']:
418 for b in opts['bookmark']:
419 # explicit pull overrides local bookmark if any
419 # explicit pull overrides local bookmark if any
420 ui.status(_("importing bookmark %s\n") % b)
420 ui.status(_("importing bookmark %s\n") % b)
421 repo._bookmarks[b] = repo[rb[b]].node()
421 repo._bookmarks[b] = repo[rb[b]].node()
422 write(repo)
422 write(repo)
423
423
424 return result
424 return result
425
425
426 def push(oldpush, ui, repo, dest=None, **opts):
426 def push(oldpush, ui, repo, dest=None, **opts):
427 dopush = True
427 dopush = True
428 if opts.get('bookmark'):
428 if opts.get('bookmark'):
429 dopush = False
429 dopush = False
430 for b in opts['bookmark']:
430 for b in opts['bookmark']:
431 if b in repo._bookmarks:
431 if b in repo._bookmarks:
432 dopush = True
432 dopush = True
433 opts.setdefault('rev', []).append(b)
433 opts.setdefault('rev', []).append(b)
434
434
435 result = 0
435 result = 0
436 if dopush:
436 if dopush:
437 result = oldpush(ui, repo, dest, **opts)
437 result = oldpush(ui, repo, dest, **opts)
438
438
439 if opts.get('bookmark'):
439 if opts.get('bookmark'):
440 # this is an unpleasant hack as push will do this internally
440 # this is an unpleasant hack as push will do this internally
441 dest = ui.expandpath(dest or 'default-push', dest or 'default')
441 dest = ui.expandpath(dest or 'default-push', dest or 'default')
442 dest, branches = hg.parseurl(dest, opts.get('branch'))
442 dest, branches = hg.parseurl(dest, opts.get('branch'))
443 other = hg.repository(hg.remoteui(repo, opts), dest)
443 other = hg.repository(hg.remoteui(repo, opts), dest)
444 rb = other.listkeys('bookmarks')
444 rb = other.listkeys('bookmarks')
445 for b in opts['bookmark']:
445 for b in opts['bookmark']:
446 # explicit push overrides remote bookmark if any
446 # explicit push overrides remote bookmark if any
447 if b in repo._bookmarks:
447 if b in repo._bookmarks:
448 ui.status(_("exporting bookmark %s\n") % b)
448 ui.status(_("exporting bookmark %s\n") % b)
449 new = repo[b].hex()
449 new = repo[b].hex()
450 elif b in rb:
450 elif b in rb:
451 ui.status(_("deleting remote bookmark %s\n") % b)
451 ui.status(_("deleting remote bookmark %s\n") % b)
452 new = '' # delete
452 new = '' # delete
453 else:
453 else:
454 ui.warn(_('bookmark %s does not exist on the local'
454 ui.warn(_('bookmark %s does not exist on the local'
455 ' or remote repository!\n') % b)
455 ' or remote repository!\n') % b)
456 return 2
456 return 2
457 old = rb.get(b, '')
457 old = rb.get(b, '')
458 r = other.pushkey('bookmarks', b, old, new)
458 r = other.pushkey('bookmarks', b, old, new)
459 if not r:
459 if not r:
460 ui.warn(_('updating bookmark %s failed!\n') % b)
460 ui.warn(_('updating bookmark %s failed!\n') % b)
461 if not result:
461 if not result:
462 result = 2
462 result = 2
463
463
464 return result
464 return result
465
465
466 def diffbookmarks(ui, repo, remote):
466 def diffbookmarks(ui, repo, remote):
467 ui.status(_("searching for changes\n"))
467 ui.status(_("searching for changes\n"))
468
468
469 lmarks = repo.listkeys('bookmarks')
469 lmarks = repo.listkeys('bookmarks')
470 rmarks = remote.listkeys('bookmarks')
470 rmarks = remote.listkeys('bookmarks')
471
471
472 diff = sorted(set(rmarks) - set(lmarks))
472 diff = sorted(set(rmarks) - set(lmarks))
473 for k in diff:
473 for k in diff:
474 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
474 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
475
475
476 if len(diff) <= 0:
476 if len(diff) <= 0:
477 ui.status(_("no changes found\n"))
477 ui.status(_("no changes found\n"))
478 return 1
478 return 1
479 return 0
479 return 0
480
480
481 def incoming(oldincoming, ui, repo, source="default", **opts):
481 def incoming(oldincoming, ui, repo, source="default", **opts):
482 if opts.get('bookmarks'):
482 if opts.get('bookmarks'):
483 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
483 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
484 other = hg.repository(hg.remoteui(repo, opts), source)
484 other = hg.repository(hg.remoteui(repo, opts), source)
485 ui.status(_('comparing with %s\n') % url.hidepassword(source))
485 ui.status(_('comparing with %s\n') % url.hidepassword(source))
486 return diffbookmarks(ui, repo, other)
486 return diffbookmarks(ui, repo, other)
487 else:
487 else:
488 return oldincoming(ui, repo, source, **opts)
488 return oldincoming(ui, repo, source, **opts)
489
489
490 def outgoing(oldoutgoing, ui, repo, dest=None, **opts):
490 def outgoing(oldoutgoing, ui, repo, dest=None, **opts):
491 if opts.get('bookmarks'):
491 if opts.get('bookmarks'):
492 dest = ui.expandpath(dest or 'default-push', dest or 'default')
492 dest = ui.expandpath(dest or 'default-push', dest or 'default')
493 dest, branches = hg.parseurl(dest, opts.get('branch'))
493 dest, branches = hg.parseurl(dest, opts.get('branch'))
494 other = hg.repository(hg.remoteui(repo, opts), dest)
494 other = hg.repository(hg.remoteui(repo, opts), dest)
495 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
495 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
496 return diffbookmarks(ui, other, repo)
496 return diffbookmarks(ui, other, repo)
497 else:
497 else:
498 return oldoutgoing(ui, repo, dest, **opts)
498 return oldoutgoing(ui, repo, dest, **opts)
499
499
500 def uisetup(ui):
500 def uisetup(ui):
501 extensions.wrapfunction(repair, "strip", strip)
501 extensions.wrapfunction(repair, "strip", strip)
502 if ui.configbool('bookmarks', 'track.current'):
502 if ui.configbool('bookmarks', 'track.current'):
503 extensions.wrapcommand(commands.table, 'update', updatecurbookmark)
503 extensions.wrapcommand(commands.table, 'update', updatecurbookmark)
504
504
505 entry = extensions.wrapcommand(commands.table, 'pull', pull)
505 entry = extensions.wrapcommand(commands.table, 'pull', pull)
506 entry[1].append(('B', 'bookmark', [],
506 entry[1].append(('B', 'bookmark', [],
507 _("bookmark to import")))
507 _("bookmark to import")))
508 entry = extensions.wrapcommand(commands.table, 'push', push)
508 entry = extensions.wrapcommand(commands.table, 'push', push)
509 entry[1].append(('B', 'bookmark', [],
509 entry[1].append(('B', 'bookmark', [],
510 _("bookmark to export")))
510 _("bookmark to export")))
511 entry = extensions.wrapcommand(commands.table, 'incoming', incoming)
511 entry = extensions.wrapcommand(commands.table, 'incoming', incoming)
512 entry[1].append(('B', 'bookmarks', False,
512 entry[1].append(('B', 'bookmarks', False,
513 _("compare bookmark")))
513 _("compare bookmark")))
514 entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
514 entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
515 entry[1].append(('B', 'bookmarks', False,
515 entry[1].append(('B', 'bookmarks', False,
516 _("compare bookmark")))
516 _("compare bookmark")))
517
517
518 pushkey.register('bookmarks', pushbookmark, listbookmarks)
518 pushkey.register('bookmarks', pushbookmark, listbookmarks)
519
519
520 def updatecurbookmark(orig, ui, repo, *args, **opts):
520 def updatecurbookmark(orig, ui, repo, *args, **opts):
521 '''Set the current bookmark
521 '''Set the current bookmark
522
522
523 If the user updates to a bookmark we update the .hg/bookmarks.current
523 If the user updates to a bookmark we update the .hg/bookmarks.current
524 file.
524 file.
525 '''
525 '''
526 res = orig(ui, repo, *args, **opts)
526 res = orig(ui, repo, *args, **opts)
527 rev = opts['rev']
527 rev = opts['rev']
528 if not rev and len(args) > 0:
528 if not rev and len(args) > 0:
529 rev = args[0]
529 rev = args[0]
530 setcurrent(repo, rev)
530 setcurrent(repo, rev)
531 return res
531 return res
532
532
533 cmdtable = {
533 cmdtable = {
534 "bookmarks":
534 "bookmarks":
535 (bookmark,
535 (bookmark,
536 [('f', 'force', False, _('force')),
536 [('f', 'force', False, _('force')),
537 ('r', 'rev', '', _('revision'), _('REV')),
537 ('r', 'rev', '', _('revision'), _('REV')),
538 ('d', 'delete', False, _('delete a given bookmark')),
538 ('d', 'delete', False, _('delete a given bookmark')),
539 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
539 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
540 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
540 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
541 }
541 }
542
542
543 colortable = {'bookmarks.current': 'green'}
543 colortable = {'bookmarks.current': 'green'}
@@ -1,298 +1,298 b''
1 # color.py color output for the status and qseries commands
1 # color.py color output for the status and qseries commands
2 #
2 #
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify it
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
8 # option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
13 # Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License along
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
19 '''colorize output from some commands
19 '''colorize output from some commands
20
20
21 This extension modifies the status and resolve commands to add color to their
21 This extension modifies the status and resolve commands to add color to their
22 output to reflect file status, the qseries command to add color to reflect
22 output to reflect file status, the qseries command to add color to reflect
23 patch status (applied, unapplied, missing), and to diff-related
23 patch status (applied, unapplied, missing), and to diff-related
24 commands to highlight additions, removals, diff headers, and trailing
24 commands to highlight additions, removals, diff headers, and trailing
25 whitespace.
25 whitespace.
26
26
27 Other effects in addition to color, like bold and underlined text, are
27 Other effects in addition to color, like bold and underlined text, are
28 also available. Effects are rendered with the ECMA-48 SGR control
28 also available. Effects are rendered with the ECMA-48 SGR control
29 function (aka ANSI escape codes). This module also provides the
29 function (aka ANSI escape codes). This module also provides the
30 render_text function, which can be used to add effects to any text.
30 render_text function, which can be used to add effects to any text.
31
31
32 Default effects may be overridden from the .hgrc file::
32 Default effects may be overridden from your configuration file::
33
33
34 [color]
34 [color]
35 status.modified = blue bold underline red_background
35 status.modified = blue bold underline red_background
36 status.added = green bold
36 status.added = green bold
37 status.removed = red bold blue_background
37 status.removed = red bold blue_background
38 status.deleted = cyan bold underline
38 status.deleted = cyan bold underline
39 status.unknown = magenta bold underline
39 status.unknown = magenta bold underline
40 status.ignored = black bold
40 status.ignored = black bold
41
41
42 # 'none' turns off all effects
42 # 'none' turns off all effects
43 status.clean = none
43 status.clean = none
44 status.copied = none
44 status.copied = none
45
45
46 qseries.applied = blue bold underline
46 qseries.applied = blue bold underline
47 qseries.unapplied = black bold
47 qseries.unapplied = black bold
48 qseries.missing = red bold
48 qseries.missing = red bold
49
49
50 diff.diffline = bold
50 diff.diffline = bold
51 diff.extended = cyan bold
51 diff.extended = cyan bold
52 diff.file_a = red bold
52 diff.file_a = red bold
53 diff.file_b = green bold
53 diff.file_b = green bold
54 diff.hunk = magenta
54 diff.hunk = magenta
55 diff.deleted = red
55 diff.deleted = red
56 diff.inserted = green
56 diff.inserted = green
57 diff.changed = white
57 diff.changed = white
58 diff.trailingwhitespace = bold red_background
58 diff.trailingwhitespace = bold red_background
59
59
60 resolve.unresolved = red bold
60 resolve.unresolved = red bold
61 resolve.resolved = green bold
61 resolve.resolved = green bold
62
62
63 bookmarks.current = green
63 bookmarks.current = green
64
64
65 branches.active = none
65 branches.active = none
66 branches.closed = black bold
66 branches.closed = black bold
67 branches.current = green
67 branches.current = green
68 branches.inactive = none
68 branches.inactive = none
69
69
70 The color extension will try to detect whether to use ANSI codes or
70 The color extension will try to detect whether to use ANSI codes or
71 Win32 console APIs, unless it is made explicit::
71 Win32 console APIs, unless it is made explicit::
72
72
73 [color]
73 [color]
74 mode = ansi
74 mode = ansi
75
75
76 Any value other than 'ansi', 'win32', or 'auto' will disable color.
76 Any value other than 'ansi', 'win32', or 'auto' will disable color.
77
77
78 '''
78 '''
79
79
80 import os
80 import os
81
81
82 from mercurial import commands, dispatch, extensions, ui as uimod
82 from mercurial import commands, dispatch, extensions, ui as uimod
83 from mercurial.i18n import _
83 from mercurial.i18n import _
84
84
85 # start and stop parameters for effects
85 # start and stop parameters for effects
86 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
86 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
87 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
87 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
88 'italic': 3, 'underline': 4, 'inverse': 7,
88 'italic': 3, 'underline': 4, 'inverse': 7,
89 'black_background': 40, 'red_background': 41,
89 'black_background': 40, 'red_background': 41,
90 'green_background': 42, 'yellow_background': 43,
90 'green_background': 42, 'yellow_background': 43,
91 'blue_background': 44, 'purple_background': 45,
91 'blue_background': 44, 'purple_background': 45,
92 'cyan_background': 46, 'white_background': 47}
92 'cyan_background': 46, 'white_background': 47}
93
93
94 _styles = {'grep.match': 'red bold',
94 _styles = {'grep.match': 'red bold',
95 'branches.active': 'none',
95 'branches.active': 'none',
96 'branches.closed': 'black bold',
96 'branches.closed': 'black bold',
97 'branches.current': 'green',
97 'branches.current': 'green',
98 'branches.inactive': 'none',
98 'branches.inactive': 'none',
99 'diff.changed': 'white',
99 'diff.changed': 'white',
100 'diff.deleted': 'red',
100 'diff.deleted': 'red',
101 'diff.diffline': 'bold',
101 'diff.diffline': 'bold',
102 'diff.extended': 'cyan bold',
102 'diff.extended': 'cyan bold',
103 'diff.file_a': 'red bold',
103 'diff.file_a': 'red bold',
104 'diff.file_b': 'green bold',
104 'diff.file_b': 'green bold',
105 'diff.hunk': 'magenta',
105 'diff.hunk': 'magenta',
106 'diff.inserted': 'green',
106 'diff.inserted': 'green',
107 'diff.trailingwhitespace': 'bold red_background',
107 'diff.trailingwhitespace': 'bold red_background',
108 'diffstat.deleted': 'red',
108 'diffstat.deleted': 'red',
109 'diffstat.inserted': 'green',
109 'diffstat.inserted': 'green',
110 'log.changeset': 'yellow',
110 'log.changeset': 'yellow',
111 'resolve.resolved': 'green bold',
111 'resolve.resolved': 'green bold',
112 'resolve.unresolved': 'red bold',
112 'resolve.unresolved': 'red bold',
113 'status.added': 'green bold',
113 'status.added': 'green bold',
114 'status.clean': 'none',
114 'status.clean': 'none',
115 'status.copied': 'none',
115 'status.copied': 'none',
116 'status.deleted': 'cyan bold underline',
116 'status.deleted': 'cyan bold underline',
117 'status.ignored': 'black bold',
117 'status.ignored': 'black bold',
118 'status.modified': 'blue bold',
118 'status.modified': 'blue bold',
119 'status.removed': 'red bold',
119 'status.removed': 'red bold',
120 'status.unknown': 'magenta bold underline'}
120 'status.unknown': 'magenta bold underline'}
121
121
122
122
123 def render_effects(text, effects):
123 def render_effects(text, effects):
124 'Wrap text in commands to turn on each effect.'
124 'Wrap text in commands to turn on each effect.'
125 if not text:
125 if not text:
126 return text
126 return text
127 start = [str(_effects[e]) for e in ['none'] + effects.split()]
127 start = [str(_effects[e]) for e in ['none'] + effects.split()]
128 start = '\033[' + ';'.join(start) + 'm'
128 start = '\033[' + ';'.join(start) + 'm'
129 stop = '\033[' + str(_effects['none']) + 'm'
129 stop = '\033[' + str(_effects['none']) + 'm'
130 return ''.join([start, text, stop])
130 return ''.join([start, text, stop])
131
131
132 def extstyles():
132 def extstyles():
133 for name, ext in extensions.extensions():
133 for name, ext in extensions.extensions():
134 _styles.update(getattr(ext, 'colortable', {}))
134 _styles.update(getattr(ext, 'colortable', {}))
135
135
136 def configstyles(ui):
136 def configstyles(ui):
137 for status, cfgeffects in ui.configitems('color'):
137 for status, cfgeffects in ui.configitems('color'):
138 if '.' not in status:
138 if '.' not in status:
139 continue
139 continue
140 cfgeffects = ui.configlist('color', status)
140 cfgeffects = ui.configlist('color', status)
141 if cfgeffects:
141 if cfgeffects:
142 good = []
142 good = []
143 for e in cfgeffects:
143 for e in cfgeffects:
144 if e in _effects:
144 if e in _effects:
145 good.append(e)
145 good.append(e)
146 else:
146 else:
147 ui.warn(_("ignoring unknown color/effect %r "
147 ui.warn(_("ignoring unknown color/effect %r "
148 "(configured in color.%s)\n")
148 "(configured in color.%s)\n")
149 % (e, status))
149 % (e, status))
150 _styles[status] = ' '.join(good)
150 _styles[status] = ' '.join(good)
151
151
152 class colorui(uimod.ui):
152 class colorui(uimod.ui):
153 def popbuffer(self, labeled=False):
153 def popbuffer(self, labeled=False):
154 if labeled:
154 if labeled:
155 return ''.join(self.label(a, label) for a, label
155 return ''.join(self.label(a, label) for a, label
156 in self._buffers.pop())
156 in self._buffers.pop())
157 return ''.join(a for a, label in self._buffers.pop())
157 return ''.join(a for a, label in self._buffers.pop())
158
158
159 _colormode = 'ansi'
159 _colormode = 'ansi'
160 def write(self, *args, **opts):
160 def write(self, *args, **opts):
161 label = opts.get('label', '')
161 label = opts.get('label', '')
162 if self._buffers:
162 if self._buffers:
163 self._buffers[-1].extend([(str(a), label) for a in args])
163 self._buffers[-1].extend([(str(a), label) for a in args])
164 elif self._colormode == 'win32':
164 elif self._colormode == 'win32':
165 for a in args:
165 for a in args:
166 win32print(a, super(colorui, self).write, **opts)
166 win32print(a, super(colorui, self).write, **opts)
167 else:
167 else:
168 return super(colorui, self).write(
168 return super(colorui, self).write(
169 *[self.label(str(a), label) for a in args], **opts)
169 *[self.label(str(a), label) for a in args], **opts)
170
170
171 def write_err(self, *args, **opts):
171 def write_err(self, *args, **opts):
172 label = opts.get('label', '')
172 label = opts.get('label', '')
173 if self._colormode == 'win32':
173 if self._colormode == 'win32':
174 for a in args:
174 for a in args:
175 win32print(a, super(colorui, self).write_err, **opts)
175 win32print(a, super(colorui, self).write_err, **opts)
176 else:
176 else:
177 return super(colorui, self).write_err(
177 return super(colorui, self).write_err(
178 *[self.label(str(a), label) for a in args], **opts)
178 *[self.label(str(a), label) for a in args], **opts)
179
179
180 def label(self, msg, label):
180 def label(self, msg, label):
181 effects = []
181 effects = []
182 for l in label.split():
182 for l in label.split():
183 s = _styles.get(l, '')
183 s = _styles.get(l, '')
184 if s:
184 if s:
185 effects.append(s)
185 effects.append(s)
186 effects = ''.join(effects)
186 effects = ''.join(effects)
187 if effects:
187 if effects:
188 return '\n'.join([render_effects(s, effects)
188 return '\n'.join([render_effects(s, effects)
189 for s in msg.split('\n')])
189 for s in msg.split('\n')])
190 return msg
190 return msg
191
191
192
192
193 def uisetup(ui):
193 def uisetup(ui):
194 if ui.plain():
194 if ui.plain():
195 return
195 return
196 mode = ui.config('color', 'mode', 'auto')
196 mode = ui.config('color', 'mode', 'auto')
197 if mode == 'auto':
197 if mode == 'auto':
198 if os.name == 'nt' and 'TERM' not in os.environ:
198 if os.name == 'nt' and 'TERM' not in os.environ:
199 # looks line a cmd.exe console, use win32 API or nothing
199 # looks line a cmd.exe console, use win32 API or nothing
200 mode = w32effects and 'win32' or 'none'
200 mode = w32effects and 'win32' or 'none'
201 else:
201 else:
202 mode = 'ansi'
202 mode = 'ansi'
203 if mode == 'win32':
203 if mode == 'win32':
204 if w32effects is None:
204 if w32effects is None:
205 # only warn if color.mode is explicitly set to win32
205 # only warn if color.mode is explicitly set to win32
206 ui.warn(_('win32console not found, please install pywin32\n'))
206 ui.warn(_('win32console not found, please install pywin32\n'))
207 return
207 return
208 _effects.update(w32effects)
208 _effects.update(w32effects)
209 elif mode != 'ansi':
209 elif mode != 'ansi':
210 return
210 return
211 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
211 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
212 if (opts['color'] == 'always' or
212 if (opts['color'] == 'always' or
213 (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb'
213 (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb'
214 and ui_.formatted()))):
214 and ui_.formatted()))):
215 colorui._colormode = mode
215 colorui._colormode = mode
216 colorui.__bases__ = (ui_.__class__,)
216 colorui.__bases__ = (ui_.__class__,)
217 ui_.__class__ = colorui
217 ui_.__class__ = colorui
218 extstyles()
218 extstyles()
219 configstyles(ui_)
219 configstyles(ui_)
220 return orig(ui_, opts, cmd, cmdfunc)
220 return orig(ui_, opts, cmd, cmdfunc)
221 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
221 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
222
222
223 commands.globalopts.append(('', 'color', 'auto',
223 commands.globalopts.append(('', 'color', 'auto',
224 _("when to colorize (always, auto, or never)"),
224 _("when to colorize (always, auto, or never)"),
225 _('TYPE')))
225 _('TYPE')))
226
226
227 try:
227 try:
228 import re, pywintypes, win32console as win32c
228 import re, pywintypes, win32console as win32c
229
229
230 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
230 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
231 w32effects = {
231 w32effects = {
232 'none': 0,
232 'none': 0,
233 'black': 0,
233 'black': 0,
234 'red': win32c.FOREGROUND_RED,
234 'red': win32c.FOREGROUND_RED,
235 'green': win32c.FOREGROUND_GREEN,
235 'green': win32c.FOREGROUND_GREEN,
236 'yellow': win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN,
236 'yellow': win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN,
237 'blue': win32c.FOREGROUND_BLUE,
237 'blue': win32c.FOREGROUND_BLUE,
238 'magenta': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_RED,
238 'magenta': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_RED,
239 'cyan': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_GREEN,
239 'cyan': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_GREEN,
240 'white': (win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN |
240 'white': (win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN |
241 win32c.FOREGROUND_BLUE),
241 win32c.FOREGROUND_BLUE),
242 'bold': win32c.FOREGROUND_INTENSITY,
242 'bold': win32c.FOREGROUND_INTENSITY,
243 'black_background': 0,
243 'black_background': 0,
244 'red_background': win32c.BACKGROUND_RED,
244 'red_background': win32c.BACKGROUND_RED,
245 'green_background': win32c.BACKGROUND_GREEN,
245 'green_background': win32c.BACKGROUND_GREEN,
246 'yellow_background': win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN,
246 'yellow_background': win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN,
247 'blue_background': win32c.BACKGROUND_BLUE,
247 'blue_background': win32c.BACKGROUND_BLUE,
248 'purple_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_RED,
248 'purple_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_RED,
249 'cyan_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_GREEN,
249 'cyan_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_GREEN,
250 'white_background': (win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN |
250 'white_background': (win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN |
251 win32c.BACKGROUND_BLUE),
251 win32c.BACKGROUND_BLUE),
252 'bold_background': win32c.BACKGROUND_INTENSITY,
252 'bold_background': win32c.BACKGROUND_INTENSITY,
253 'underline': win32c.COMMON_LVB_UNDERSCORE, # double-byte charsets only
253 'underline': win32c.COMMON_LVB_UNDERSCORE, # double-byte charsets only
254 'inverse': win32c.COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
254 'inverse': win32c.COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
255 }
255 }
256
256
257 try:
257 try:
258 stdout = win32c.GetStdHandle(win32c.STD_OUTPUT_HANDLE)
258 stdout = win32c.GetStdHandle(win32c.STD_OUTPUT_HANDLE)
259 if stdout is None:
259 if stdout is None:
260 raise ImportError()
260 raise ImportError()
261 origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
261 origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
262 except pywintypes.error:
262 except pywintypes.error:
263 # stdout may be defined but not support
263 # stdout may be defined but not support
264 # GetConsoleScreenBufferInfo(), when called from subprocess or
264 # GetConsoleScreenBufferInfo(), when called from subprocess or
265 # redirected.
265 # redirected.
266 raise ImportError()
266 raise ImportError()
267 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
267 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
268
268
269 def win32print(text, orig, **opts):
269 def win32print(text, orig, **opts):
270 label = opts.get('label', '')
270 label = opts.get('label', '')
271 attr = 0
271 attr = 0
272
272
273 # determine console attributes based on labels
273 # determine console attributes based on labels
274 for l in label.split():
274 for l in label.split():
275 style = _styles.get(l, '')
275 style = _styles.get(l, '')
276 for effect in style.split():
276 for effect in style.split():
277 attr |= w32effects[effect]
277 attr |= w32effects[effect]
278
278
279 # hack to ensure regexp finds data
279 # hack to ensure regexp finds data
280 if not text.startswith('\033['):
280 if not text.startswith('\033['):
281 text = '\033[m' + text
281 text = '\033[m' + text
282
282
283 # Look for ANSI-like codes embedded in text
283 # Look for ANSI-like codes embedded in text
284 m = re.match(ansire, text)
284 m = re.match(ansire, text)
285 while m:
285 while m:
286 for sattr in m.group(1).split(';'):
286 for sattr in m.group(1).split(';'):
287 if sattr:
287 if sattr:
288 val = int(sattr)
288 val = int(sattr)
289 attr = val and attr|val or 0
289 attr = val and attr|val or 0
290 stdout.SetConsoleTextAttribute(attr or origattr)
290 stdout.SetConsoleTextAttribute(attr or origattr)
291 orig(m.group(2), **opts)
291 orig(m.group(2), **opts)
292 m = re.match(ansire, m.group(3))
292 m = re.match(ansire, m.group(3))
293
293
294 # Explicity reset original attributes
294 # Explicity reset original attributes
295 stdout.SetConsoleTextAttribute(origattr)
295 stdout.SetConsoleTextAttribute(origattr)
296
296
297 except ImportError:
297 except ImportError:
298 w32effects = None
298 w32effects = None
@@ -1,348 +1,348 b''
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.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 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''browse the repository in a graphical way
8 '''browse the repository in a graphical way
9
9
10 The hgk extension allows browsing the history of a repository in a
10 The hgk extension allows browsing the history of a repository in a
11 graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is not
11 graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is not
12 distributed with Mercurial.)
12 distributed with Mercurial.)
13
13
14 hgk consists of two parts: a Tcl script that does the displaying and
14 hgk consists of two parts: a Tcl script that does the displaying and
15 querying of information, and an extension to Mercurial named hgk.py,
15 querying of information, and an extension to Mercurial named hgk.py,
16 which provides hooks for hgk to get information. hgk can be found in
16 which provides hooks for hgk to get information. hgk can be found in
17 the contrib directory, and the extension is shipped in the hgext
17 the contrib directory, and the extension is shipped in the hgext
18 repository, and needs to be enabled.
18 repository, and needs to be enabled.
19
19
20 The :hg:`view` command will launch the hgk Tcl script. For this command
20 The :hg:`view` command will launch the hgk Tcl script. For this command
21 to work, hgk must be in your search path. Alternately, you can specify
21 to work, hgk must be in your search path. Alternately, you can specify
22 the path to hgk in your .hgrc file::
22 the path to hgk in your configuration file::
23
23
24 [hgk]
24 [hgk]
25 path=/location/of/hgk
25 path=/location/of/hgk
26
26
27 hgk can make use of the extdiff extension to visualize revisions.
27 hgk can make use of the extdiff extension to visualize revisions.
28 Assuming you had already configured extdiff vdiff command, just add::
28 Assuming you had already configured extdiff vdiff command, just add::
29
29
30 [hgk]
30 [hgk]
31 vdiff=vdiff
31 vdiff=vdiff
32
32
33 Revisions context menu will now display additional entries to fire
33 Revisions context menu will now display additional entries to fire
34 vdiff on hovered and selected revisions.
34 vdiff on hovered and selected revisions.
35 '''
35 '''
36
36
37 import os
37 import os
38 from mercurial import commands, util, patch, revlog, cmdutil
38 from mercurial import commands, util, patch, revlog, cmdutil
39 from mercurial.node import nullid, nullrev, short
39 from mercurial.node import nullid, nullrev, short
40 from mercurial.i18n import _
40 from mercurial.i18n import _
41
41
42 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
42 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
43 """diff trees from two commits"""
43 """diff trees from two commits"""
44 def __difftree(repo, node1, node2, files=[]):
44 def __difftree(repo, node1, node2, files=[]):
45 assert node2 is not None
45 assert node2 is not None
46 mmap = repo[node1].manifest()
46 mmap = repo[node1].manifest()
47 mmap2 = repo[node2].manifest()
47 mmap2 = repo[node2].manifest()
48 m = cmdutil.match(repo, files)
48 m = cmdutil.match(repo, files)
49 modified, added, removed = repo.status(node1, node2, m)[:3]
49 modified, added, removed = repo.status(node1, node2, m)[:3]
50 empty = short(nullid)
50 empty = short(nullid)
51
51
52 for f in modified:
52 for f in modified:
53 # TODO get file permissions
53 # TODO get file permissions
54 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
54 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
55 (short(mmap[f]), short(mmap2[f]), f, f))
55 (short(mmap[f]), short(mmap2[f]), f, f))
56 for f in added:
56 for f in added:
57 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
57 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
58 (empty, short(mmap2[f]), f, f))
58 (empty, short(mmap2[f]), f, f))
59 for f in removed:
59 for f in removed:
60 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
60 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
61 (short(mmap[f]), empty, f, f))
61 (short(mmap[f]), empty, f, f))
62 ##
62 ##
63
63
64 while True:
64 while True:
65 if opts['stdin']:
65 if opts['stdin']:
66 try:
66 try:
67 line = raw_input().split(' ')
67 line = raw_input().split(' ')
68 node1 = line[0]
68 node1 = line[0]
69 if len(line) > 1:
69 if len(line) > 1:
70 node2 = line[1]
70 node2 = line[1]
71 else:
71 else:
72 node2 = None
72 node2 = None
73 except EOFError:
73 except EOFError:
74 break
74 break
75 node1 = repo.lookup(node1)
75 node1 = repo.lookup(node1)
76 if node2:
76 if node2:
77 node2 = repo.lookup(node2)
77 node2 = repo.lookup(node2)
78 else:
78 else:
79 node2 = node1
79 node2 = node1
80 node1 = repo.changelog.parents(node1)[0]
80 node1 = repo.changelog.parents(node1)[0]
81 if opts['patch']:
81 if opts['patch']:
82 if opts['pretty']:
82 if opts['pretty']:
83 catcommit(ui, repo, node2, "")
83 catcommit(ui, repo, node2, "")
84 m = cmdutil.match(repo, files)
84 m = cmdutil.match(repo, files)
85 chunks = patch.diff(repo, node1, node2, match=m,
85 chunks = patch.diff(repo, node1, node2, match=m,
86 opts=patch.diffopts(ui, {'git': True}))
86 opts=patch.diffopts(ui, {'git': True}))
87 for chunk in chunks:
87 for chunk in chunks:
88 ui.write(chunk)
88 ui.write(chunk)
89 else:
89 else:
90 __difftree(repo, node1, node2, files=files)
90 __difftree(repo, node1, node2, files=files)
91 if not opts['stdin']:
91 if not opts['stdin']:
92 break
92 break
93
93
94 def catcommit(ui, repo, n, prefix, ctx=None):
94 def catcommit(ui, repo, n, prefix, ctx=None):
95 nlprefix = '\n' + prefix
95 nlprefix = '\n' + prefix
96 if ctx is None:
96 if ctx is None:
97 ctx = repo[n]
97 ctx = repo[n]
98 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
98 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
99 for p in ctx.parents():
99 for p in ctx.parents():
100 ui.write("parent %s\n" % p)
100 ui.write("parent %s\n" % p)
101
101
102 date = ctx.date()
102 date = ctx.date()
103 description = ctx.description().replace("\0", "")
103 description = ctx.description().replace("\0", "")
104 lines = description.splitlines()
104 lines = description.splitlines()
105 if lines and lines[-1].startswith('committer:'):
105 if lines and lines[-1].startswith('committer:'):
106 committer = lines[-1].split(': ')[1].rstrip()
106 committer = lines[-1].split(': ')[1].rstrip()
107 else:
107 else:
108 committer = ctx.user()
108 committer = ctx.user()
109
109
110 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
110 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
111 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
111 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
112 ui.write("revision %d\n" % ctx.rev())
112 ui.write("revision %d\n" % ctx.rev())
113 ui.write("branch %s\n\n" % ctx.branch())
113 ui.write("branch %s\n\n" % ctx.branch())
114
114
115 if prefix != "":
115 if prefix != "":
116 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
116 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
117 else:
117 else:
118 ui.write(description + "\n")
118 ui.write(description + "\n")
119 if prefix:
119 if prefix:
120 ui.write('\0')
120 ui.write('\0')
121
121
122 def base(ui, repo, node1, node2):
122 def base(ui, repo, node1, node2):
123 """output common ancestor information"""
123 """output common ancestor information"""
124 node1 = repo.lookup(node1)
124 node1 = repo.lookup(node1)
125 node2 = repo.lookup(node2)
125 node2 = repo.lookup(node2)
126 n = repo.changelog.ancestor(node1, node2)
126 n = repo.changelog.ancestor(node1, node2)
127 ui.write(short(n) + "\n")
127 ui.write(short(n) + "\n")
128
128
129 def catfile(ui, repo, type=None, r=None, **opts):
129 def catfile(ui, repo, type=None, r=None, **opts):
130 """cat a specific revision"""
130 """cat a specific revision"""
131 # in stdin mode, every line except the commit is prefixed with two
131 # in stdin mode, every line except the commit is prefixed with two
132 # spaces. This way the our caller can find the commit without magic
132 # spaces. This way the our caller can find the commit without magic
133 # strings
133 # strings
134 #
134 #
135 prefix = ""
135 prefix = ""
136 if opts['stdin']:
136 if opts['stdin']:
137 try:
137 try:
138 (type, r) = raw_input().split(' ')
138 (type, r) = raw_input().split(' ')
139 prefix = " "
139 prefix = " "
140 except EOFError:
140 except EOFError:
141 return
141 return
142
142
143 else:
143 else:
144 if not type or not r:
144 if not type or not r:
145 ui.warn(_("cat-file: type or revision not supplied\n"))
145 ui.warn(_("cat-file: type or revision not supplied\n"))
146 commands.help_(ui, 'cat-file')
146 commands.help_(ui, 'cat-file')
147
147
148 while r:
148 while r:
149 if type != "commit":
149 if type != "commit":
150 ui.warn(_("aborting hg cat-file only understands commits\n"))
150 ui.warn(_("aborting hg cat-file only understands commits\n"))
151 return 1
151 return 1
152 n = repo.lookup(r)
152 n = repo.lookup(r)
153 catcommit(ui, repo, n, prefix)
153 catcommit(ui, repo, n, prefix)
154 if opts['stdin']:
154 if opts['stdin']:
155 try:
155 try:
156 (type, r) = raw_input().split(' ')
156 (type, r) = raw_input().split(' ')
157 except EOFError:
157 except EOFError:
158 break
158 break
159 else:
159 else:
160 break
160 break
161
161
162 # git rev-tree is a confusing thing. You can supply a number of
162 # git rev-tree is a confusing thing. You can supply a number of
163 # commit sha1s on the command line, and it walks the commit history
163 # commit sha1s on the command line, and it walks the commit history
164 # telling you which commits are reachable from the supplied ones via
164 # telling you which commits are reachable from the supplied ones via
165 # a bitmask based on arg position.
165 # a bitmask based on arg position.
166 # you can specify a commit to stop at by starting the sha1 with ^
166 # you can specify a commit to stop at by starting the sha1 with ^
167 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
167 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
168 def chlogwalk():
168 def chlogwalk():
169 count = len(repo)
169 count = len(repo)
170 i = count
170 i = count
171 l = [0] * 100
171 l = [0] * 100
172 chunk = 100
172 chunk = 100
173 while True:
173 while True:
174 if chunk > i:
174 if chunk > i:
175 chunk = i
175 chunk = i
176 i = 0
176 i = 0
177 else:
177 else:
178 i -= chunk
178 i -= chunk
179
179
180 for x in xrange(chunk):
180 for x in xrange(chunk):
181 if i + x >= count:
181 if i + x >= count:
182 l[chunk - x:] = [0] * (chunk - x)
182 l[chunk - x:] = [0] * (chunk - x)
183 break
183 break
184 if full != None:
184 if full != None:
185 l[x] = repo[i + x]
185 l[x] = repo[i + x]
186 l[x].changeset() # force reading
186 l[x].changeset() # force reading
187 else:
187 else:
188 l[x] = 1
188 l[x] = 1
189 for x in xrange(chunk - 1, -1, -1):
189 for x in xrange(chunk - 1, -1, -1):
190 if l[x] != 0:
190 if l[x] != 0:
191 yield (i + x, full != None and l[x] or None)
191 yield (i + x, full != None and l[x] or None)
192 if i == 0:
192 if i == 0:
193 break
193 break
194
194
195 # calculate and return the reachability bitmask for sha
195 # calculate and return the reachability bitmask for sha
196 def is_reachable(ar, reachable, sha):
196 def is_reachable(ar, reachable, sha):
197 if len(ar) == 0:
197 if len(ar) == 0:
198 return 1
198 return 1
199 mask = 0
199 mask = 0
200 for i in xrange(len(ar)):
200 for i in xrange(len(ar)):
201 if sha in reachable[i]:
201 if sha in reachable[i]:
202 mask |= 1 << i
202 mask |= 1 << i
203
203
204 return mask
204 return mask
205
205
206 reachable = []
206 reachable = []
207 stop_sha1 = []
207 stop_sha1 = []
208 want_sha1 = []
208 want_sha1 = []
209 count = 0
209 count = 0
210
210
211 # figure out which commits they are asking for and which ones they
211 # figure out which commits they are asking for and which ones they
212 # want us to stop on
212 # want us to stop on
213 for i, arg in enumerate(args):
213 for i, arg in enumerate(args):
214 if arg.startswith('^'):
214 if arg.startswith('^'):
215 s = repo.lookup(arg[1:])
215 s = repo.lookup(arg[1:])
216 stop_sha1.append(s)
216 stop_sha1.append(s)
217 want_sha1.append(s)
217 want_sha1.append(s)
218 elif arg != 'HEAD':
218 elif arg != 'HEAD':
219 want_sha1.append(repo.lookup(arg))
219 want_sha1.append(repo.lookup(arg))
220
220
221 # calculate the graph for the supplied commits
221 # calculate the graph for the supplied commits
222 for i, n in enumerate(want_sha1):
222 for i, n in enumerate(want_sha1):
223 reachable.append(set())
223 reachable.append(set())
224 visit = [n]
224 visit = [n]
225 reachable[i].add(n)
225 reachable[i].add(n)
226 while visit:
226 while visit:
227 n = visit.pop(0)
227 n = visit.pop(0)
228 if n in stop_sha1:
228 if n in stop_sha1:
229 continue
229 continue
230 for p in repo.changelog.parents(n):
230 for p in repo.changelog.parents(n):
231 if p not in reachable[i]:
231 if p not in reachable[i]:
232 reachable[i].add(p)
232 reachable[i].add(p)
233 visit.append(p)
233 visit.append(p)
234 if p in stop_sha1:
234 if p in stop_sha1:
235 continue
235 continue
236
236
237 # walk the repository looking for commits that are in our
237 # walk the repository looking for commits that are in our
238 # reachability graph
238 # reachability graph
239 for i, ctx in chlogwalk():
239 for i, ctx in chlogwalk():
240 n = repo.changelog.node(i)
240 n = repo.changelog.node(i)
241 mask = is_reachable(want_sha1, reachable, n)
241 mask = is_reachable(want_sha1, reachable, n)
242 if mask:
242 if mask:
243 parentstr = ""
243 parentstr = ""
244 if parents:
244 if parents:
245 pp = repo.changelog.parents(n)
245 pp = repo.changelog.parents(n)
246 if pp[0] != nullid:
246 if pp[0] != nullid:
247 parentstr += " " + short(pp[0])
247 parentstr += " " + short(pp[0])
248 if pp[1] != nullid:
248 if pp[1] != nullid:
249 parentstr += " " + short(pp[1])
249 parentstr += " " + short(pp[1])
250 if not full:
250 if not full:
251 ui.write("%s%s\n" % (short(n), parentstr))
251 ui.write("%s%s\n" % (short(n), parentstr))
252 elif full == "commit":
252 elif full == "commit":
253 ui.write("%s%s\n" % (short(n), parentstr))
253 ui.write("%s%s\n" % (short(n), parentstr))
254 catcommit(ui, repo, n, ' ', ctx)
254 catcommit(ui, repo, n, ' ', ctx)
255 else:
255 else:
256 (p1, p2) = repo.changelog.parents(n)
256 (p1, p2) = repo.changelog.parents(n)
257 (h, h1, h2) = map(short, (n, p1, p2))
257 (h, h1, h2) = map(short, (n, p1, p2))
258 (i1, i2) = map(repo.changelog.rev, (p1, p2))
258 (i1, i2) = map(repo.changelog.rev, (p1, p2))
259
259
260 date = ctx.date()[0]
260 date = ctx.date()[0]
261 ui.write("%s %s:%s" % (date, h, mask))
261 ui.write("%s %s:%s" % (date, h, mask))
262 mask = is_reachable(want_sha1, reachable, p1)
262 mask = is_reachable(want_sha1, reachable, p1)
263 if i1 != nullrev and mask > 0:
263 if i1 != nullrev and mask > 0:
264 ui.write("%s:%s " % (h1, mask)),
264 ui.write("%s:%s " % (h1, mask)),
265 mask = is_reachable(want_sha1, reachable, p2)
265 mask = is_reachable(want_sha1, reachable, p2)
266 if i2 != nullrev and mask > 0:
266 if i2 != nullrev and mask > 0:
267 ui.write("%s:%s " % (h2, mask))
267 ui.write("%s:%s " % (h2, mask))
268 ui.write("\n")
268 ui.write("\n")
269 if maxnr and count >= maxnr:
269 if maxnr and count >= maxnr:
270 break
270 break
271 count += 1
271 count += 1
272
272
273 def revparse(ui, repo, *revs, **opts):
273 def revparse(ui, repo, *revs, **opts):
274 """parse given revisions"""
274 """parse given revisions"""
275 def revstr(rev):
275 def revstr(rev):
276 if rev == 'HEAD':
276 if rev == 'HEAD':
277 rev = 'tip'
277 rev = 'tip'
278 return revlog.hex(repo.lookup(rev))
278 return revlog.hex(repo.lookup(rev))
279
279
280 for r in revs:
280 for r in revs:
281 revrange = r.split(':', 1)
281 revrange = r.split(':', 1)
282 ui.write('%s\n' % revstr(revrange[0]))
282 ui.write('%s\n' % revstr(revrange[0]))
283 if len(revrange) == 2:
283 if len(revrange) == 2:
284 ui.write('^%s\n' % revstr(revrange[1]))
284 ui.write('^%s\n' % revstr(revrange[1]))
285
285
286 # git rev-list tries to order things by date, and has the ability to stop
286 # git rev-list tries to order things by date, and has the ability to stop
287 # at a given commit without walking the whole repo. TODO add the stop
287 # at a given commit without walking the whole repo. TODO add the stop
288 # parameter
288 # parameter
289 def revlist(ui, repo, *revs, **opts):
289 def revlist(ui, repo, *revs, **opts):
290 """print revisions"""
290 """print revisions"""
291 if opts['header']:
291 if opts['header']:
292 full = "commit"
292 full = "commit"
293 else:
293 else:
294 full = None
294 full = None
295 copy = [x for x in revs]
295 copy = [x for x in revs]
296 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
296 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
297
297
298 def config(ui, repo, **opts):
298 def config(ui, repo, **opts):
299 """print extension options"""
299 """print extension options"""
300 def writeopt(name, value):
300 def writeopt(name, value):
301 ui.write('k=%s\nv=%s\n' % (name, value))
301 ui.write('k=%s\nv=%s\n' % (name, value))
302
302
303 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
303 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
304
304
305
305
306 def view(ui, repo, *etc, **opts):
306 def view(ui, repo, *etc, **opts):
307 "start interactive history viewer"
307 "start interactive history viewer"
308 os.chdir(repo.root)
308 os.chdir(repo.root)
309 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
309 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
310 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
310 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
311 ui.debug("running %s\n" % cmd)
311 ui.debug("running %s\n" % cmd)
312 util.system(cmd)
312 util.system(cmd)
313
313
314 cmdtable = {
314 cmdtable = {
315 "^view":
315 "^view":
316 (view,
316 (view,
317 [('l', 'limit', '',
317 [('l', 'limit', '',
318 _('limit number of changes displayed'), _('NUM'))],
318 _('limit number of changes displayed'), _('NUM'))],
319 _('hg view [-l LIMIT] [REVRANGE]')),
319 _('hg view [-l LIMIT] [REVRANGE]')),
320 "debug-diff-tree":
320 "debug-diff-tree":
321 (difftree,
321 (difftree,
322 [('p', 'patch', None, _('generate patch')),
322 [('p', 'patch', None, _('generate patch')),
323 ('r', 'recursive', None, _('recursive')),
323 ('r', 'recursive', None, _('recursive')),
324 ('P', 'pretty', None, _('pretty')),
324 ('P', 'pretty', None, _('pretty')),
325 ('s', 'stdin', None, _('stdin')),
325 ('s', 'stdin', None, _('stdin')),
326 ('C', 'copy', None, _('detect copies')),
326 ('C', 'copy', None, _('detect copies')),
327 ('S', 'search', "", _('search'))],
327 ('S', 'search', "", _('search'))],
328 _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')),
328 _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')),
329 "debug-cat-file":
329 "debug-cat-file":
330 (catfile,
330 (catfile,
331 [('s', 'stdin', None, _('stdin'))],
331 [('s', 'stdin', None, _('stdin'))],
332 _('hg debug-cat-file [OPTION]... TYPE FILE')),
332 _('hg debug-cat-file [OPTION]... TYPE FILE')),
333 "debug-config":
333 "debug-config":
334 (config, [], _('hg debug-config')),
334 (config, [], _('hg debug-config')),
335 "debug-merge-base":
335 "debug-merge-base":
336 (base, [], _('hg debug-merge-base REV REV')),
336 (base, [], _('hg debug-merge-base REV REV')),
337 "debug-rev-parse":
337 "debug-rev-parse":
338 (revparse,
338 (revparse,
339 [('', 'default', '', _('ignored'))],
339 [('', 'default', '', _('ignored'))],
340 _('hg debug-rev-parse REV')),
340 _('hg debug-rev-parse REV')),
341 "debug-rev-list":
341 "debug-rev-list":
342 (revlist,
342 (revlist,
343 [('H', 'header', None, _('header')),
343 [('H', 'header', None, _('header')),
344 ('t', 'topo-order', None, _('topo-order')),
344 ('t', 'topo-order', None, _('topo-order')),
345 ('p', 'parents', None, _('parents')),
345 ('p', 'parents', None, _('parents')),
346 ('n', 'max-count', 0, _('max-count'))],
346 ('n', 'max-count', 0, _('max-count'))],
347 _('hg debug-rev-list [OPTION]... REV...')),
347 _('hg debug-rev-list [OPTION]... REV...')),
348 }
348 }
@@ -1,99 +1,99 b''
1 # pager.py - display output using a pager
1 # pager.py - display output using a pager
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.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 or any later version.
6 # GNU General Public License version 2 or any later version.
7 #
7 #
8 # To load the extension, add it to your .hgrc file:
8 # To load the extension, add it to your configuration file:
9 #
9 #
10 # [extension]
10 # [extension]
11 # pager =
11 # pager =
12 #
12 #
13 # Run "hg help pager" to get info on configuration.
13 # Run "hg help pager" to get info on configuration.
14
14
15 '''browse command output with an external pager
15 '''browse command output with an external pager
16
16
17 To set the pager that should be used, set the application variable::
17 To set the pager that should be used, set the application variable::
18
18
19 [pager]
19 [pager]
20 pager = LESS='FSRX' less
20 pager = LESS='FSRX' less
21
21
22 If no pager is set, the pager extensions uses the environment variable
22 If no pager is set, the pager extensions uses the environment variable
23 $PAGER. If neither pager.pager, nor $PAGER is set, no pager is used.
23 $PAGER. If neither pager.pager, nor $PAGER is set, no pager is used.
24
24
25 If you notice "BROKEN PIPE" error messages, you can disable them by
25 If you notice "BROKEN PIPE" error messages, you can disable them by
26 setting::
26 setting::
27
27
28 [pager]
28 [pager]
29 quiet = True
29 quiet = True
30
30
31 You can disable the pager for certain commands by adding them to the
31 You can disable the pager for certain commands by adding them to the
32 pager.ignore list::
32 pager.ignore list::
33
33
34 [pager]
34 [pager]
35 ignore = version, help, update
35 ignore = version, help, update
36
36
37 You can also enable the pager only for certain commands using
37 You can also enable the pager only for certain commands using
38 pager.attend. Below is the default list of commands to be paged::
38 pager.attend. Below is the default list of commands to be paged::
39
39
40 [pager]
40 [pager]
41 attend = annotate, cat, diff, export, glog, log, qdiff
41 attend = annotate, cat, diff, export, glog, log, qdiff
42
42
43 Setting pager.attend to an empty value will cause all commands to be
43 Setting pager.attend to an empty value will cause all commands to be
44 paged.
44 paged.
45
45
46 If pager.attend is present, pager.ignore will be ignored.
46 If pager.attend is present, pager.ignore will be ignored.
47
47
48 To ignore global commands like :hg:`version` or :hg:`help`, you have
48 To ignore global commands like :hg:`version` or :hg:`help`, you have
49 to specify them in the global .hgrc
49 to specify them in your user configuration file.
50 '''
50 '''
51
51
52 import sys, os, signal, shlex, errno
52 import sys, os, signal, shlex, errno
53 from mercurial import dispatch, util, extensions
53 from mercurial import dispatch, util, extensions
54
54
55 def _runpager(p):
55 def _runpager(p):
56 if not hasattr(os, 'fork'):
56 if not hasattr(os, 'fork'):
57 sys.stderr = sys.stdout = util.popen(p, 'wb')
57 sys.stderr = sys.stdout = util.popen(p, 'wb')
58 return
58 return
59 fdin, fdout = os.pipe()
59 fdin, fdout = os.pipe()
60 pid = os.fork()
60 pid = os.fork()
61 if pid == 0:
61 if pid == 0:
62 os.close(fdin)
62 os.close(fdin)
63 os.dup2(fdout, sys.stdout.fileno())
63 os.dup2(fdout, sys.stdout.fileno())
64 os.dup2(fdout, sys.stderr.fileno())
64 os.dup2(fdout, sys.stderr.fileno())
65 os.close(fdout)
65 os.close(fdout)
66 return
66 return
67 os.dup2(fdin, sys.stdin.fileno())
67 os.dup2(fdin, sys.stdin.fileno())
68 os.close(fdin)
68 os.close(fdin)
69 os.close(fdout)
69 os.close(fdout)
70 try:
70 try:
71 os.execvp('/bin/sh', ['/bin/sh', '-c', p])
71 os.execvp('/bin/sh', ['/bin/sh', '-c', p])
72 except OSError, e:
72 except OSError, e:
73 if e.errno == errno.ENOENT:
73 if e.errno == errno.ENOENT:
74 # no /bin/sh, try executing the pager directly
74 # no /bin/sh, try executing the pager directly
75 args = shlex.split(p)
75 args = shlex.split(p)
76 os.execvp(args[0], args)
76 os.execvp(args[0], args)
77 else:
77 else:
78 raise
78 raise
79
79
80 def uisetup(ui):
80 def uisetup(ui):
81 if ui.plain():
81 if ui.plain():
82 return
82 return
83
83
84 def pagecmd(orig, ui, options, cmd, cmdfunc):
84 def pagecmd(orig, ui, options, cmd, cmdfunc):
85 p = ui.config("pager", "pager", os.environ.get("PAGER"))
85 p = ui.config("pager", "pager", os.environ.get("PAGER"))
86 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
86 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
87 attend = ui.configlist('pager', 'attend', attended)
87 attend = ui.configlist('pager', 'attend', attended)
88 if (cmd in attend or
88 if (cmd in attend or
89 (cmd not in ui.configlist('pager', 'ignore') and not attend)):
89 (cmd not in ui.configlist('pager', 'ignore') and not attend)):
90 ui.setconfig('ui', 'formatted', ui.formatted())
90 ui.setconfig('ui', 'formatted', ui.formatted())
91 ui.setconfig('ui', 'interactive', False)
91 ui.setconfig('ui', 'interactive', False)
92 _runpager(p)
92 _runpager(p)
93 if ui.configbool('pager', 'quiet'):
93 if ui.configbool('pager', 'quiet'):
94 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
94 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
95 return orig(ui, options, cmd, cmdfunc)
95 return orig(ui, options, cmd, cmdfunc)
96
96
97 extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
97 extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
98
98
99 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
99 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
@@ -1,4476 +1,4479 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 or any later version.
6 # GNU General Public License version 2 or any later version.
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, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, bundlerepo, extensions, copies, error
12 import hg, util, revlog, bundlerepo, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
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
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 bad = []
49 bad = []
50 names = []
50 names = []
51 m = cmdutil.match(repo, pats, opts)
51 m = cmdutil.match(repo, pats, opts)
52 oldbad = m.bad
52 oldbad = m.bad
53 m.bad = lambda x, y: bad.append(x) or oldbad(x, y)
53 m.bad = lambda x, y: bad.append(x) or oldbad(x, y)
54
54
55 for f in repo.walk(m):
55 for f in repo.walk(m):
56 exact = m.exact(f)
56 exact = m.exact(f)
57 if exact or f not in repo.dirstate:
57 if exact or f not in repo.dirstate:
58 names.append(f)
58 names.append(f)
59 if ui.verbose or not exact:
59 if ui.verbose or not exact:
60 ui.status(_('adding %s\n') % m.rel(f))
60 ui.status(_('adding %s\n') % m.rel(f))
61 if not opts.get('dry_run'):
61 if not opts.get('dry_run'):
62 bad += [f for f in repo[None].add(names) if f in m.files()]
62 bad += [f for f in repo[None].add(names) if f in m.files()]
63 return bad and 1 or 0
63 return bad and 1 or 0
64
64
65 def addremove(ui, repo, *pats, **opts):
65 def addremove(ui, repo, *pats, **opts):
66 """add all new files, delete all missing files
66 """add all new files, delete all missing files
67
67
68 Add all new files and remove all missing files from the
68 Add all new files and remove all missing files from the
69 repository.
69 repository.
70
70
71 New files are ignored if they match any of the patterns in
71 New files are ignored if they match any of the patterns in
72 .hgignore. As with add, these changes take effect at the next
72 .hgignore. As with add, these changes take effect at the next
73 commit.
73 commit.
74
74
75 Use the -s/--similarity option to detect renamed files. With a
75 Use the -s/--similarity option to detect renamed files. With a
76 parameter greater than 0, this compares every removed file with
76 parameter greater than 0, this compares every removed file with
77 every added file and records those similar enough as renames. This
77 every added file and records those similar enough as renames. This
78 option takes a percentage between 0 (disabled) and 100 (files must
78 option takes a percentage between 0 (disabled) and 100 (files must
79 be identical) as its parameter. Detecting renamed files this way
79 be identical) as its parameter. Detecting renamed files this way
80 can be expensive. After using this option, :hg:`status -C` can be
80 can be expensive. After using this option, :hg:`status -C` can be
81 used to check which files were identified as moved or renamed.
81 used to check which files were identified as moved or renamed.
82
82
83 Returns 0 if all files are successfully added.
83 Returns 0 if all files are successfully added.
84 """
84 """
85 try:
85 try:
86 sim = float(opts.get('similarity') or 100)
86 sim = float(opts.get('similarity') or 100)
87 except ValueError:
87 except ValueError:
88 raise util.Abort(_('similarity must be a number'))
88 raise util.Abort(_('similarity must be a number'))
89 if sim < 0 or sim > 100:
89 if sim < 0 or sim > 100:
90 raise util.Abort(_('similarity must be between 0 and 100'))
90 raise util.Abort(_('similarity must be between 0 and 100'))
91 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
91 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
92
92
93 def annotate(ui, repo, *pats, **opts):
93 def annotate(ui, repo, *pats, **opts):
94 """show changeset information by line for each file
94 """show changeset information by line for each file
95
95
96 List changes in files, showing the revision id responsible for
96 List changes in files, showing the revision id responsible for
97 each line
97 each line
98
98
99 This command is useful for discovering when a change was made and
99 This command is useful for discovering when a change was made and
100 by whom.
100 by whom.
101
101
102 Without the -a/--text option, annotate will avoid processing files
102 Without the -a/--text option, annotate will avoid processing files
103 it detects as binary. With -a, annotate will annotate the file
103 it detects as binary. With -a, annotate will annotate the file
104 anyway, although the results will probably be neither useful
104 anyway, although the results will probably be neither useful
105 nor desirable.
105 nor desirable.
106
106
107 Returns 0 on success.
107 Returns 0 on success.
108 """
108 """
109 if opts.get('follow'):
109 if opts.get('follow'):
110 # --follow is deprecated and now just an alias for -f/--file
110 # --follow is deprecated and now just an alias for -f/--file
111 # to mimic the behavior of Mercurial before version 1.5
111 # to mimic the behavior of Mercurial before version 1.5
112 opts['file'] = 1
112 opts['file'] = 1
113
113
114 datefunc = ui.quiet and util.shortdate or util.datestr
114 datefunc = ui.quiet and util.shortdate or util.datestr
115 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
115 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
116
116
117 if not pats:
117 if not pats:
118 raise util.Abort(_('at least one filename or pattern is required'))
118 raise util.Abort(_('at least one filename or pattern is required'))
119
119
120 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
120 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
121 ('number', lambda x: str(x[0].rev())),
121 ('number', lambda x: str(x[0].rev())),
122 ('changeset', lambda x: short(x[0].node())),
122 ('changeset', lambda x: short(x[0].node())),
123 ('date', getdate),
123 ('date', getdate),
124 ('file', lambda x: x[0].path()),
124 ('file', lambda x: x[0].path()),
125 ]
125 ]
126
126
127 if (not opts.get('user') and not opts.get('changeset')
127 if (not opts.get('user') and not opts.get('changeset')
128 and not opts.get('date') and not opts.get('file')):
128 and not opts.get('date') and not opts.get('file')):
129 opts['number'] = 1
129 opts['number'] = 1
130
130
131 linenumber = opts.get('line_number') is not None
131 linenumber = opts.get('line_number') is not None
132 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
132 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
133 raise util.Abort(_('at least one of -n/-c is required for -l'))
133 raise util.Abort(_('at least one of -n/-c is required for -l'))
134
134
135 funcmap = [func for op, func in opmap if opts.get(op)]
135 funcmap = [func for op, func in opmap if opts.get(op)]
136 if linenumber:
136 if linenumber:
137 lastfunc = funcmap[-1]
137 lastfunc = funcmap[-1]
138 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
138 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
139
139
140 ctx = repo[opts.get('rev')]
140 ctx = repo[opts.get('rev')]
141 m = cmdutil.match(repo, pats, opts)
141 m = cmdutil.match(repo, pats, opts)
142 follow = not opts.get('no_follow')
142 follow = not opts.get('no_follow')
143 for abs in ctx.walk(m):
143 for abs in ctx.walk(m):
144 fctx = ctx[abs]
144 fctx = ctx[abs]
145 if not opts.get('text') and util.binary(fctx.data()):
145 if not opts.get('text') and util.binary(fctx.data()):
146 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
146 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
147 continue
147 continue
148
148
149 lines = fctx.annotate(follow=follow, linenumber=linenumber)
149 lines = fctx.annotate(follow=follow, linenumber=linenumber)
150 pieces = []
150 pieces = []
151
151
152 for f in funcmap:
152 for f in funcmap:
153 l = [f(n) for n, dummy in lines]
153 l = [f(n) for n, dummy in lines]
154 if l:
154 if l:
155 sized = [(x, encoding.colwidth(x)) for x in l]
155 sized = [(x, encoding.colwidth(x)) for x in l]
156 ml = max([w for x, w in sized])
156 ml = max([w for x, w in sized])
157 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
157 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
158
158
159 if pieces:
159 if pieces:
160 for p, l in zip(zip(*pieces), lines):
160 for p, l in zip(zip(*pieces), lines):
161 ui.write("%s: %s" % (" ".join(p), l[1]))
161 ui.write("%s: %s" % (" ".join(p), l[1]))
162
162
163 def archive(ui, repo, dest, **opts):
163 def archive(ui, repo, dest, **opts):
164 '''create an unversioned archive of a repository revision
164 '''create an unversioned archive of a repository revision
165
165
166 By default, the revision used is the parent of the working
166 By default, the revision used is the parent of the working
167 directory; use -r/--rev to specify a different revision.
167 directory; use -r/--rev to specify a different revision.
168
168
169 The archive type is automatically detected based on file
169 The archive type is automatically detected based on file
170 extension (or override using -t/--type).
170 extension (or override using -t/--type).
171
171
172 Valid types are:
172 Valid types are:
173
173
174 :``files``: a directory full of files (default)
174 :``files``: a directory full of files (default)
175 :``tar``: tar archive, uncompressed
175 :``tar``: tar archive, uncompressed
176 :``tbz2``: tar archive, compressed using bzip2
176 :``tbz2``: tar archive, compressed using bzip2
177 :``tgz``: tar archive, compressed using gzip
177 :``tgz``: tar archive, compressed using gzip
178 :``uzip``: zip archive, uncompressed
178 :``uzip``: zip archive, uncompressed
179 :``zip``: zip archive, compressed using deflate
179 :``zip``: zip archive, compressed using deflate
180
180
181 The exact name of the destination archive or directory is given
181 The exact name of the destination archive or directory is given
182 using a format string; see :hg:`help export` for details.
182 using a format string; see :hg:`help export` for details.
183
183
184 Each member added to an archive file has a directory prefix
184 Each member added to an archive file has a directory prefix
185 prepended. Use -p/--prefix to specify a format string for the
185 prepended. Use -p/--prefix to specify a format string for the
186 prefix. The default is the basename of the archive, with suffixes
186 prefix. The default is the basename of the archive, with suffixes
187 removed.
187 removed.
188
188
189 Returns 0 on success.
189 Returns 0 on success.
190 '''
190 '''
191
191
192 ctx = repo[opts.get('rev')]
192 ctx = repo[opts.get('rev')]
193 if not ctx:
193 if not ctx:
194 raise util.Abort(_('no working directory: please specify a revision'))
194 raise util.Abort(_('no working directory: please specify a revision'))
195 node = ctx.node()
195 node = ctx.node()
196 dest = cmdutil.make_filename(repo, dest, node)
196 dest = cmdutil.make_filename(repo, dest, node)
197 if os.path.realpath(dest) == repo.root:
197 if os.path.realpath(dest) == repo.root:
198 raise util.Abort(_('repository root cannot be destination'))
198 raise util.Abort(_('repository root cannot be destination'))
199
199
200 kind = opts.get('type') or archival.guesskind(dest) or 'files'
200 kind = opts.get('type') or archival.guesskind(dest) or 'files'
201 prefix = opts.get('prefix')
201 prefix = opts.get('prefix')
202
202
203 if dest == '-':
203 if dest == '-':
204 if kind == 'files':
204 if kind == 'files':
205 raise util.Abort(_('cannot archive plain files to stdout'))
205 raise util.Abort(_('cannot archive plain files to stdout'))
206 dest = sys.stdout
206 dest = sys.stdout
207 if not prefix:
207 if not prefix:
208 prefix = os.path.basename(repo.root) + '-%h'
208 prefix = os.path.basename(repo.root) + '-%h'
209
209
210 prefix = cmdutil.make_filename(repo, prefix, node)
210 prefix = cmdutil.make_filename(repo, prefix, node)
211 matchfn = cmdutil.match(repo, [], opts)
211 matchfn = cmdutil.match(repo, [], opts)
212 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
212 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
213 matchfn, prefix)
213 matchfn, prefix)
214
214
215 def backout(ui, repo, node=None, rev=None, **opts):
215 def backout(ui, repo, node=None, rev=None, **opts):
216 '''reverse effect of earlier changeset
216 '''reverse effect of earlier changeset
217
217
218 Commit the backed out changes as a new changeset. The new
218 Commit the backed out changes as a new changeset. The new
219 changeset is a child of the backed out changeset.
219 changeset is a child of the backed out changeset.
220
220
221 If you backout a changeset other than the tip, a new head is
221 If you backout a changeset other than the tip, a new head is
222 created. This head will be the new tip and you should merge this
222 created. This head will be the new tip and you should merge this
223 backout changeset with another head.
223 backout changeset with another head.
224
224
225 The --merge option remembers the parent of the working directory
225 The --merge option remembers the parent of the working directory
226 before starting the backout, then merges the new head with that
226 before starting the backout, then merges the new head with that
227 changeset afterwards. This saves you from doing the merge by hand.
227 changeset afterwards. This saves you from doing the merge by hand.
228 The result of this merge is not committed, as with a normal merge.
228 The result of this merge is not committed, as with a normal merge.
229
229
230 See :hg:`help dates` for a list of formats valid for -d/--date.
230 See :hg:`help dates` for a list of formats valid for -d/--date.
231
231
232 Returns 0 on success.
232 Returns 0 on success.
233 '''
233 '''
234 if rev and node:
234 if rev and node:
235 raise util.Abort(_("please specify just one revision"))
235 raise util.Abort(_("please specify just one revision"))
236
236
237 if not rev:
237 if not rev:
238 rev = node
238 rev = node
239
239
240 if not rev:
240 if not rev:
241 raise util.Abort(_("please specify a revision to backout"))
241 raise util.Abort(_("please specify a revision to backout"))
242
242
243 date = opts.get('date')
243 date = opts.get('date')
244 if date:
244 if date:
245 opts['date'] = util.parsedate(date)
245 opts['date'] = util.parsedate(date)
246
246
247 cmdutil.bail_if_changed(repo)
247 cmdutil.bail_if_changed(repo)
248 node = repo.lookup(rev)
248 node = repo.lookup(rev)
249
249
250 op1, op2 = repo.dirstate.parents()
250 op1, op2 = repo.dirstate.parents()
251 a = repo.changelog.ancestor(op1, node)
251 a = repo.changelog.ancestor(op1, node)
252 if a != node:
252 if a != node:
253 raise util.Abort(_('cannot backout change on a different branch'))
253 raise util.Abort(_('cannot backout change on a different branch'))
254
254
255 p1, p2 = repo.changelog.parents(node)
255 p1, p2 = repo.changelog.parents(node)
256 if p1 == nullid:
256 if p1 == nullid:
257 raise util.Abort(_('cannot backout a change with no parents'))
257 raise util.Abort(_('cannot backout a change with no parents'))
258 if p2 != nullid:
258 if p2 != nullid:
259 if not opts.get('parent'):
259 if not opts.get('parent'):
260 raise util.Abort(_('cannot backout a merge changeset without '
260 raise util.Abort(_('cannot backout a merge changeset without '
261 '--parent'))
261 '--parent'))
262 p = repo.lookup(opts['parent'])
262 p = repo.lookup(opts['parent'])
263 if p not in (p1, p2):
263 if p not in (p1, p2):
264 raise util.Abort(_('%s is not a parent of %s') %
264 raise util.Abort(_('%s is not a parent of %s') %
265 (short(p), short(node)))
265 (short(p), short(node)))
266 parent = p
266 parent = p
267 else:
267 else:
268 if opts.get('parent'):
268 if opts.get('parent'):
269 raise util.Abort(_('cannot use --parent on non-merge changeset'))
269 raise util.Abort(_('cannot use --parent on non-merge changeset'))
270 parent = p1
270 parent = p1
271
271
272 # the backout should appear on the same branch
272 # the backout should appear on the same branch
273 branch = repo.dirstate.branch()
273 branch = repo.dirstate.branch()
274 hg.clean(repo, node, show_stats=False)
274 hg.clean(repo, node, show_stats=False)
275 repo.dirstate.setbranch(branch)
275 repo.dirstate.setbranch(branch)
276 revert_opts = opts.copy()
276 revert_opts = opts.copy()
277 revert_opts['date'] = None
277 revert_opts['date'] = None
278 revert_opts['all'] = True
278 revert_opts['all'] = True
279 revert_opts['rev'] = hex(parent)
279 revert_opts['rev'] = hex(parent)
280 revert_opts['no_backup'] = None
280 revert_opts['no_backup'] = None
281 revert(ui, repo, **revert_opts)
281 revert(ui, repo, **revert_opts)
282 commit_opts = opts.copy()
282 commit_opts = opts.copy()
283 commit_opts['addremove'] = False
283 commit_opts['addremove'] = False
284 if not commit_opts['message'] and not commit_opts['logfile']:
284 if not commit_opts['message'] and not commit_opts['logfile']:
285 # we don't translate commit messages
285 # we don't translate commit messages
286 commit_opts['message'] = "Backed out changeset %s" % short(node)
286 commit_opts['message'] = "Backed out changeset %s" % short(node)
287 commit_opts['force_editor'] = True
287 commit_opts['force_editor'] = True
288 commit(ui, repo, **commit_opts)
288 commit(ui, repo, **commit_opts)
289 def nice(node):
289 def nice(node):
290 return '%d:%s' % (repo.changelog.rev(node), short(node))
290 return '%d:%s' % (repo.changelog.rev(node), short(node))
291 ui.status(_('changeset %s backs out changeset %s\n') %
291 ui.status(_('changeset %s backs out changeset %s\n') %
292 (nice(repo.changelog.tip()), nice(node)))
292 (nice(repo.changelog.tip()), nice(node)))
293 if op1 != node:
293 if op1 != node:
294 hg.clean(repo, op1, show_stats=False)
294 hg.clean(repo, op1, show_stats=False)
295 if opts.get('merge'):
295 if opts.get('merge'):
296 ui.status(_('merging with changeset %s\n')
296 ui.status(_('merging with changeset %s\n')
297 % nice(repo.changelog.tip()))
297 % nice(repo.changelog.tip()))
298 hg.merge(repo, hex(repo.changelog.tip()))
298 hg.merge(repo, hex(repo.changelog.tip()))
299 else:
299 else:
300 ui.status(_('the backout changeset is a new head - '
300 ui.status(_('the backout changeset is a new head - '
301 'do not forget to merge\n'))
301 'do not forget to merge\n'))
302 ui.status(_('(use "backout --merge" '
302 ui.status(_('(use "backout --merge" '
303 'if you want to auto-merge)\n'))
303 'if you want to auto-merge)\n'))
304
304
305 def bisect(ui, repo, rev=None, extra=None, command=None,
305 def bisect(ui, repo, rev=None, extra=None, command=None,
306 reset=None, good=None, bad=None, skip=None, noupdate=None):
306 reset=None, good=None, bad=None, skip=None, noupdate=None):
307 """subdivision search of changesets
307 """subdivision search of changesets
308
308
309 This command helps to find changesets which introduce problems. To
309 This command helps to find changesets which introduce problems. To
310 use, mark the earliest changeset you know exhibits the problem as
310 use, mark the earliest changeset you know exhibits the problem as
311 bad, then mark the latest changeset which is free from the problem
311 bad, then mark the latest changeset which is free from the problem
312 as good. Bisect will update your working directory to a revision
312 as good. Bisect will update your working directory to a revision
313 for testing (unless the -U/--noupdate option is specified). Once
313 for testing (unless the -U/--noupdate option is specified). Once
314 you have performed tests, mark the working directory as good or
314 you have performed tests, mark the working directory as good or
315 bad, and bisect will either update to another candidate changeset
315 bad, and bisect will either update to another candidate changeset
316 or announce that it has found the bad revision.
316 or announce that it has found the bad revision.
317
317
318 As a shortcut, you can also use the revision argument to mark a
318 As a shortcut, you can also use the revision argument to mark a
319 revision as good or bad without checking it out first.
319 revision as good or bad without checking it out first.
320
320
321 If you supply a command, it will be used for automatic bisection.
321 If you supply a command, it will be used for automatic bisection.
322 Its exit status will be used to mark revisions as good or bad:
322 Its exit status will be used to mark revisions as good or bad:
323 status 0 means good, 125 means to skip the revision, 127
323 status 0 means good, 125 means to skip the revision, 127
324 (command not found) will abort the bisection, and any other
324 (command not found) will abort the bisection, and any other
325 non-zero exit status means the revision is bad.
325 non-zero exit status means the revision is bad.
326
326
327 Returns 0 on success.
327 Returns 0 on success.
328 """
328 """
329 def print_result(nodes, good):
329 def print_result(nodes, good):
330 displayer = cmdutil.show_changeset(ui, repo, {})
330 displayer = cmdutil.show_changeset(ui, repo, {})
331 if len(nodes) == 1:
331 if len(nodes) == 1:
332 # narrowed it down to a single revision
332 # narrowed it down to a single revision
333 if good:
333 if good:
334 ui.write(_("The first good revision is:\n"))
334 ui.write(_("The first good revision is:\n"))
335 else:
335 else:
336 ui.write(_("The first bad revision is:\n"))
336 ui.write(_("The first bad revision is:\n"))
337 displayer.show(repo[nodes[0]])
337 displayer.show(repo[nodes[0]])
338 else:
338 else:
339 # multiple possible revisions
339 # multiple possible revisions
340 if good:
340 if good:
341 ui.write(_("Due to skipped revisions, the first "
341 ui.write(_("Due to skipped revisions, the first "
342 "good revision could be any of:\n"))
342 "good revision could be any of:\n"))
343 else:
343 else:
344 ui.write(_("Due to skipped revisions, the first "
344 ui.write(_("Due to skipped revisions, the first "
345 "bad revision could be any of:\n"))
345 "bad revision could be any of:\n"))
346 for n in nodes:
346 for n in nodes:
347 displayer.show(repo[n])
347 displayer.show(repo[n])
348 displayer.close()
348 displayer.close()
349
349
350 def check_state(state, interactive=True):
350 def check_state(state, interactive=True):
351 if not state['good'] or not state['bad']:
351 if not state['good'] or not state['bad']:
352 if (good or bad or skip or reset) and interactive:
352 if (good or bad or skip or reset) and interactive:
353 return
353 return
354 if not state['good']:
354 if not state['good']:
355 raise util.Abort(_('cannot bisect (no known good revisions)'))
355 raise util.Abort(_('cannot bisect (no known good revisions)'))
356 else:
356 else:
357 raise util.Abort(_('cannot bisect (no known bad revisions)'))
357 raise util.Abort(_('cannot bisect (no known bad revisions)'))
358 return True
358 return True
359
359
360 # backward compatibility
360 # backward compatibility
361 if rev in "good bad reset init".split():
361 if rev in "good bad reset init".split():
362 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
362 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
363 cmd, rev, extra = rev, extra, None
363 cmd, rev, extra = rev, extra, None
364 if cmd == "good":
364 if cmd == "good":
365 good = True
365 good = True
366 elif cmd == "bad":
366 elif cmd == "bad":
367 bad = True
367 bad = True
368 else:
368 else:
369 reset = True
369 reset = True
370 elif extra or good + bad + skip + reset + bool(command) > 1:
370 elif extra or good + bad + skip + reset + bool(command) > 1:
371 raise util.Abort(_('incompatible arguments'))
371 raise util.Abort(_('incompatible arguments'))
372
372
373 if reset:
373 if reset:
374 p = repo.join("bisect.state")
374 p = repo.join("bisect.state")
375 if os.path.exists(p):
375 if os.path.exists(p):
376 os.unlink(p)
376 os.unlink(p)
377 return
377 return
378
378
379 state = hbisect.load_state(repo)
379 state = hbisect.load_state(repo)
380
380
381 if command:
381 if command:
382 changesets = 1
382 changesets = 1
383 try:
383 try:
384 while changesets:
384 while changesets:
385 # update state
385 # update state
386 status = util.system(command)
386 status = util.system(command)
387 if status == 125:
387 if status == 125:
388 transition = "skip"
388 transition = "skip"
389 elif status == 0:
389 elif status == 0:
390 transition = "good"
390 transition = "good"
391 # status < 0 means process was killed
391 # status < 0 means process was killed
392 elif status == 127:
392 elif status == 127:
393 raise util.Abort(_("failed to execute %s") % command)
393 raise util.Abort(_("failed to execute %s") % command)
394 elif status < 0:
394 elif status < 0:
395 raise util.Abort(_("%s killed") % command)
395 raise util.Abort(_("%s killed") % command)
396 else:
396 else:
397 transition = "bad"
397 transition = "bad"
398 ctx = repo[rev or '.']
398 ctx = repo[rev or '.']
399 state[transition].append(ctx.node())
399 state[transition].append(ctx.node())
400 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
400 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
401 check_state(state, interactive=False)
401 check_state(state, interactive=False)
402 # bisect
402 # bisect
403 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
403 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
404 # update to next check
404 # update to next check
405 cmdutil.bail_if_changed(repo)
405 cmdutil.bail_if_changed(repo)
406 hg.clean(repo, nodes[0], show_stats=False)
406 hg.clean(repo, nodes[0], show_stats=False)
407 finally:
407 finally:
408 hbisect.save_state(repo, state)
408 hbisect.save_state(repo, state)
409 print_result(nodes, good)
409 print_result(nodes, good)
410 return
410 return
411
411
412 # update state
412 # update state
413 node = repo.lookup(rev or '.')
413 node = repo.lookup(rev or '.')
414 if good or bad or skip:
414 if good or bad or skip:
415 if good:
415 if good:
416 state['good'].append(node)
416 state['good'].append(node)
417 elif bad:
417 elif bad:
418 state['bad'].append(node)
418 state['bad'].append(node)
419 elif skip:
419 elif skip:
420 state['skip'].append(node)
420 state['skip'].append(node)
421 hbisect.save_state(repo, state)
421 hbisect.save_state(repo, state)
422
422
423 if not check_state(state):
423 if not check_state(state):
424 return
424 return
425
425
426 # actually bisect
426 # actually bisect
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
428 if changesets == 0:
428 if changesets == 0:
429 print_result(nodes, good)
429 print_result(nodes, good)
430 else:
430 else:
431 assert len(nodes) == 1 # only a single node can be tested next
431 assert len(nodes) == 1 # only a single node can be tested next
432 node = nodes[0]
432 node = nodes[0]
433 # compute the approximate number of remaining tests
433 # compute the approximate number of remaining tests
434 tests, size = 0, 2
434 tests, size = 0, 2
435 while size <= changesets:
435 while size <= changesets:
436 tests, size = tests + 1, size * 2
436 tests, size = tests + 1, size * 2
437 rev = repo.changelog.rev(node)
437 rev = repo.changelog.rev(node)
438 ui.write(_("Testing changeset %d:%s "
438 ui.write(_("Testing changeset %d:%s "
439 "(%d changesets remaining, ~%d tests)\n")
439 "(%d changesets remaining, ~%d tests)\n")
440 % (rev, short(node), changesets, tests))
440 % (rev, short(node), changesets, tests))
441 if not noupdate:
441 if not noupdate:
442 cmdutil.bail_if_changed(repo)
442 cmdutil.bail_if_changed(repo)
443 return hg.clean(repo, node)
443 return hg.clean(repo, node)
444
444
445 def branch(ui, repo, label=None, **opts):
445 def branch(ui, repo, label=None, **opts):
446 """set or show the current branch name
446 """set or show the current branch name
447
447
448 With no argument, show the current branch name. With one argument,
448 With no argument, show the current branch name. With one argument,
449 set the working directory branch name (the branch will not exist
449 set the working directory branch name (the branch will not exist
450 in the repository until the next commit). Standard practice
450 in the repository until the next commit). Standard practice
451 recommends that primary development take place on the 'default'
451 recommends that primary development take place on the 'default'
452 branch.
452 branch.
453
453
454 Unless -f/--force is specified, branch will not let you set a
454 Unless -f/--force is specified, branch will not let you set a
455 branch name that already exists, even if it's inactive.
455 branch name that already exists, even if it's inactive.
456
456
457 Use -C/--clean to reset the working directory branch to that of
457 Use -C/--clean to reset the working directory branch to that of
458 the parent of the working directory, negating a previous branch
458 the parent of the working directory, negating a previous branch
459 change.
459 change.
460
460
461 Use the command :hg:`update` to switch to an existing branch. Use
461 Use the command :hg:`update` to switch to an existing branch. Use
462 :hg:`commit --close-branch` to mark this branch as closed.
462 :hg:`commit --close-branch` to mark this branch as closed.
463
463
464 Returns 0 on success.
464 Returns 0 on success.
465 """
465 """
466
466
467 if opts.get('clean'):
467 if opts.get('clean'):
468 label = repo[None].parents()[0].branch()
468 label = repo[None].parents()[0].branch()
469 repo.dirstate.setbranch(label)
469 repo.dirstate.setbranch(label)
470 ui.status(_('reset working directory to branch %s\n') % label)
470 ui.status(_('reset working directory to branch %s\n') % label)
471 elif label:
471 elif label:
472 utflabel = encoding.fromlocal(label)
472 utflabel = encoding.fromlocal(label)
473 if not opts.get('force') and utflabel in repo.branchtags():
473 if not opts.get('force') and utflabel in repo.branchtags():
474 if label not in [p.branch() for p in repo.parents()]:
474 if label not in [p.branch() for p in repo.parents()]:
475 raise util.Abort(_('a branch of the same name already exists'
475 raise util.Abort(_('a branch of the same name already exists'
476 " (use 'hg update' to switch to it)"))
476 " (use 'hg update' to switch to it)"))
477 repo.dirstate.setbranch(utflabel)
477 repo.dirstate.setbranch(utflabel)
478 ui.status(_('marked working directory as branch %s\n') % label)
478 ui.status(_('marked working directory as branch %s\n') % label)
479 else:
479 else:
480 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
480 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
481
481
482 def branches(ui, repo, active=False, closed=False):
482 def branches(ui, repo, active=False, closed=False):
483 """list repository named branches
483 """list repository named branches
484
484
485 List the repository's named branches, indicating which ones are
485 List the repository's named branches, indicating which ones are
486 inactive. If -c/--closed is specified, also list branches which have
486 inactive. If -c/--closed is specified, also list branches which have
487 been marked closed (see :hg:`commit --close-branch`).
487 been marked closed (see :hg:`commit --close-branch`).
488
488
489 If -a/--active is specified, only show active branches. A branch
489 If -a/--active is specified, only show active branches. A branch
490 is considered active if it contains repository heads.
490 is considered active if it contains repository heads.
491
491
492 Use the command :hg:`update` to switch to an existing branch.
492 Use the command :hg:`update` to switch to an existing branch.
493
493
494 Returns 0.
494 Returns 0.
495 """
495 """
496
496
497 hexfunc = ui.debugflag and hex or short
497 hexfunc = ui.debugflag and hex or short
498 activebranches = [repo[n].branch() for n in repo.heads()]
498 activebranches = [repo[n].branch() for n in repo.heads()]
499 def testactive(tag, node):
499 def testactive(tag, node):
500 realhead = tag in activebranches
500 realhead = tag in activebranches
501 open = node in repo.branchheads(tag, closed=False)
501 open = node in repo.branchheads(tag, closed=False)
502 return realhead and open
502 return realhead and open
503 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
503 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
504 for tag, node in repo.branchtags().items()],
504 for tag, node in repo.branchtags().items()],
505 reverse=True)
505 reverse=True)
506
506
507 for isactive, node, tag in branches:
507 for isactive, node, tag in branches:
508 if (not active) or isactive:
508 if (not active) or isactive:
509 encodedtag = encoding.tolocal(tag)
509 encodedtag = encoding.tolocal(tag)
510 if ui.quiet:
510 if ui.quiet:
511 ui.write("%s\n" % encodedtag)
511 ui.write("%s\n" % encodedtag)
512 else:
512 else:
513 hn = repo.lookup(node)
513 hn = repo.lookup(node)
514 if isactive:
514 if isactive:
515 label = 'branches.active'
515 label = 'branches.active'
516 notice = ''
516 notice = ''
517 elif hn not in repo.branchheads(tag, closed=False):
517 elif hn not in repo.branchheads(tag, closed=False):
518 if not closed:
518 if not closed:
519 continue
519 continue
520 label = 'branches.closed'
520 label = 'branches.closed'
521 notice = _(' (closed)')
521 notice = _(' (closed)')
522 else:
522 else:
523 label = 'branches.inactive'
523 label = 'branches.inactive'
524 notice = _(' (inactive)')
524 notice = _(' (inactive)')
525 if tag == repo.dirstate.branch():
525 if tag == repo.dirstate.branch():
526 label = 'branches.current'
526 label = 'branches.current'
527 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
527 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
528 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
528 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
529 encodedtag = ui.label(encodedtag, label)
529 encodedtag = ui.label(encodedtag, label)
530 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
530 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
531
531
532 def bundle(ui, repo, fname, dest=None, **opts):
532 def bundle(ui, repo, fname, dest=None, **opts):
533 """create a changegroup file
533 """create a changegroup file
534
534
535 Generate a compressed changegroup file collecting changesets not
535 Generate a compressed changegroup file collecting changesets not
536 known to be in another repository.
536 known to be in another repository.
537
537
538 If you omit the destination repository, then hg assumes the
538 If you omit the destination repository, then hg assumes the
539 destination will have all the nodes you specify with --base
539 destination will have all the nodes you specify with --base
540 parameters. To create a bundle containing all changesets, use
540 parameters. To create a bundle containing all changesets, use
541 -a/--all (or --base null).
541 -a/--all (or --base null).
542
542
543 You can change compression method with the -t/--type option.
543 You can change compression method with the -t/--type option.
544 The available compression methods are: none, bzip2, and
544 The available compression methods are: none, bzip2, and
545 gzip (by default, bundles are compressed using bzip2).
545 gzip (by default, bundles are compressed using bzip2).
546
546
547 The bundle file can then be transferred using conventional means
547 The bundle file can then be transferred using conventional means
548 and applied to another repository with the unbundle or pull
548 and applied to another repository with the unbundle or pull
549 command. This is useful when direct push and pull are not
549 command. This is useful when direct push and pull are not
550 available or when exporting an entire repository is undesirable.
550 available or when exporting an entire repository is undesirable.
551
551
552 Applying bundles preserves all changeset contents including
552 Applying bundles preserves all changeset contents including
553 permissions, copy/rename information, and revision history.
553 permissions, copy/rename information, and revision history.
554
554
555 Returns 0 on success, 1 if no changes found.
555 Returns 0 on success, 1 if no changes found.
556 """
556 """
557 revs = opts.get('rev') or None
557 revs = opts.get('rev') or None
558 if opts.get('all'):
558 if opts.get('all'):
559 base = ['null']
559 base = ['null']
560 else:
560 else:
561 base = opts.get('base')
561 base = opts.get('base')
562 if base:
562 if base:
563 if dest:
563 if dest:
564 raise util.Abort(_("--base is incompatible with specifying "
564 raise util.Abort(_("--base is incompatible with specifying "
565 "a destination"))
565 "a destination"))
566 base = [repo.lookup(rev) for rev in base]
566 base = [repo.lookup(rev) for rev in base]
567 # create the right base
567 # create the right base
568 # XXX: nodesbetween / changegroup* should be "fixed" instead
568 # XXX: nodesbetween / changegroup* should be "fixed" instead
569 o = []
569 o = []
570 has = set((nullid,))
570 has = set((nullid,))
571 for n in base:
571 for n in base:
572 has.update(repo.changelog.reachable(n))
572 has.update(repo.changelog.reachable(n))
573 if revs:
573 if revs:
574 revs = [repo.lookup(rev) for rev in revs]
574 revs = [repo.lookup(rev) for rev in revs]
575 visit = revs[:]
575 visit = revs[:]
576 has.difference_update(visit)
576 has.difference_update(visit)
577 else:
577 else:
578 visit = repo.changelog.heads()
578 visit = repo.changelog.heads()
579 seen = {}
579 seen = {}
580 while visit:
580 while visit:
581 n = visit.pop(0)
581 n = visit.pop(0)
582 parents = [p for p in repo.changelog.parents(n) if p not in has]
582 parents = [p for p in repo.changelog.parents(n) if p not in has]
583 if len(parents) == 0:
583 if len(parents) == 0:
584 if n not in has:
584 if n not in has:
585 o.append(n)
585 o.append(n)
586 else:
586 else:
587 for p in parents:
587 for p in parents:
588 if p not in seen:
588 if p not in seen:
589 seen[p] = 1
589 seen[p] = 1
590 visit.append(p)
590 visit.append(p)
591 else:
591 else:
592 dest = ui.expandpath(dest or 'default-push', dest or 'default')
592 dest = ui.expandpath(dest or 'default-push', dest or 'default')
593 dest, branches = hg.parseurl(dest, opts.get('branch'))
593 dest, branches = hg.parseurl(dest, opts.get('branch'))
594 other = hg.repository(hg.remoteui(repo, opts), dest)
594 other = hg.repository(hg.remoteui(repo, opts), dest)
595 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
595 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
596 if revs:
596 if revs:
597 revs = [repo.lookup(rev) for rev in revs]
597 revs = [repo.lookup(rev) for rev in revs]
598 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
598 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
599
599
600 if not o:
600 if not o:
601 ui.status(_("no changes found\n"))
601 ui.status(_("no changes found\n"))
602 return 1
602 return 1
603
603
604 if revs:
604 if revs:
605 cg = repo.changegroupsubset(o, revs, 'bundle')
605 cg = repo.changegroupsubset(o, revs, 'bundle')
606 else:
606 else:
607 cg = repo.changegroup(o, 'bundle')
607 cg = repo.changegroup(o, 'bundle')
608
608
609 bundletype = opts.get('type', 'bzip2').lower()
609 bundletype = opts.get('type', 'bzip2').lower()
610 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
610 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
611 bundletype = btypes.get(bundletype)
611 bundletype = btypes.get(bundletype)
612 if bundletype not in changegroup.bundletypes:
612 if bundletype not in changegroup.bundletypes:
613 raise util.Abort(_('unknown bundle type specified with --type'))
613 raise util.Abort(_('unknown bundle type specified with --type'))
614
614
615 changegroup.writebundle(cg, fname, bundletype)
615 changegroup.writebundle(cg, fname, bundletype)
616
616
617 def cat(ui, repo, file1, *pats, **opts):
617 def cat(ui, repo, file1, *pats, **opts):
618 """output the current or given revision of files
618 """output the current or given revision of files
619
619
620 Print the specified files as they were at the given revision. If
620 Print the specified files as they were at the given revision. If
621 no revision is given, the parent of the working directory is used,
621 no revision is given, the parent of the working directory is used,
622 or tip if no revision is checked out.
622 or tip if no revision is checked out.
623
623
624 Output may be to a file, in which case the name of the file is
624 Output may be to a file, in which case the name of the file is
625 given using a format string. The formatting rules are the same as
625 given using a format string. The formatting rules are the same as
626 for the export command, with the following additions:
626 for the export command, with the following additions:
627
627
628 :``%s``: basename of file being printed
628 :``%s``: basename of file being printed
629 :``%d``: dirname of file being printed, or '.' if in repository root
629 :``%d``: dirname of file being printed, or '.' if in repository root
630 :``%p``: root-relative path name of file being printed
630 :``%p``: root-relative path name of file being printed
631
631
632 Returns 0 on success.
632 Returns 0 on success.
633 """
633 """
634 ctx = repo[opts.get('rev')]
634 ctx = repo[opts.get('rev')]
635 err = 1
635 err = 1
636 m = cmdutil.match(repo, (file1,) + pats, opts)
636 m = cmdutil.match(repo, (file1,) + pats, opts)
637 for abs in ctx.walk(m):
637 for abs in ctx.walk(m):
638 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
638 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
639 data = ctx[abs].data()
639 data = ctx[abs].data()
640 if opts.get('decode'):
640 if opts.get('decode'):
641 data = repo.wwritedata(abs, data)
641 data = repo.wwritedata(abs, data)
642 fp.write(data)
642 fp.write(data)
643 err = 0
643 err = 0
644 return err
644 return err
645
645
646 def clone(ui, source, dest=None, **opts):
646 def clone(ui, source, dest=None, **opts):
647 """make a copy of an existing repository
647 """make a copy of an existing repository
648
648
649 Create a copy of an existing repository in a new directory.
649 Create a copy of an existing repository in a new directory.
650
650
651 If no destination directory name is specified, it defaults to the
651 If no destination directory name is specified, it defaults to the
652 basename of the source.
652 basename of the source.
653
653
654 The location of the source is added to the new repository's
654 The location of the source is added to the new repository's
655 .hg/hgrc file, as the default to be used for future pulls.
655 .hg/hgrc file, as the default to be used for future pulls.
656
656
657 See :hg:`help urls` for valid source format details.
657 See :hg:`help urls` for valid source format details.
658
658
659 It is possible to specify an ``ssh://`` URL as the destination, but no
659 It is possible to specify an ``ssh://`` URL as the destination, but no
660 .hg/hgrc and working directory will be created on the remote side.
660 .hg/hgrc and working directory will be created on the remote side.
661 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
661 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
662
662
663 A set of changesets (tags, or branch names) to pull may be specified
663 A set of changesets (tags, or branch names) to pull may be specified
664 by listing each changeset (tag, or branch name) with -r/--rev.
664 by listing each changeset (tag, or branch name) with -r/--rev.
665 If -r/--rev is used, the cloned repository will contain only a subset
665 If -r/--rev is used, the cloned repository will contain only a subset
666 of the changesets of the source repository. Only the set of changesets
666 of the changesets of the source repository. Only the set of changesets
667 defined by all -r/--rev options (including all their ancestors)
667 defined by all -r/--rev options (including all their ancestors)
668 will be pulled into the destination repository.
668 will be pulled into the destination repository.
669 No subsequent changesets (including subsequent tags) will be present
669 No subsequent changesets (including subsequent tags) will be present
670 in the destination.
670 in the destination.
671
671
672 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
672 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
673 local source repositories.
673 local source repositories.
674
674
675 For efficiency, hardlinks are used for cloning whenever the source
675 For efficiency, hardlinks are used for cloning whenever the source
676 and destination are on the same filesystem (note this applies only
676 and destination are on the same filesystem (note this applies only
677 to the repository data, not to the working directory). Some
677 to the repository data, not to the working directory). Some
678 filesystems, such as AFS, implement hardlinking incorrectly, but
678 filesystems, such as AFS, implement hardlinking incorrectly, but
679 do not report errors. In these cases, use the --pull option to
679 do not report errors. In these cases, use the --pull option to
680 avoid hardlinking.
680 avoid hardlinking.
681
681
682 In some cases, you can clone repositories and the working directory
682 In some cases, you can clone repositories and the working directory
683 using full hardlinks with ::
683 using full hardlinks with ::
684
684
685 $ cp -al REPO REPOCLONE
685 $ cp -al REPO REPOCLONE
686
686
687 This is the fastest way to clone, but it is not always safe. The
687 This is the fastest way to clone, but it is not always safe. The
688 operation is not atomic (making sure REPO is not modified during
688 operation is not atomic (making sure REPO is not modified during
689 the operation is up to you) and you have to make sure your editor
689 the operation is up to you) and you have to make sure your editor
690 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
690 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
691 this is not compatible with certain extensions that place their
691 this is not compatible with certain extensions that place their
692 metadata under the .hg directory, such as mq.
692 metadata under the .hg directory, such as mq.
693
693
694 Mercurial will update the working directory to the first applicable
694 Mercurial will update the working directory to the first applicable
695 revision from this list:
695 revision from this list:
696
696
697 a) null if -U or the source repository has no changesets
697 a) null if -U or the source repository has no changesets
698 b) if -u . and the source repository is local, the first parent of
698 b) if -u . and the source repository is local, the first parent of
699 the source repository's working directory
699 the source repository's working directory
700 c) the changeset specified with -u (if a branch name, this means the
700 c) the changeset specified with -u (if a branch name, this means the
701 latest head of that branch)
701 latest head of that branch)
702 d) the changeset specified with -r
702 d) the changeset specified with -r
703 e) the tipmost head specified with -b
703 e) the tipmost head specified with -b
704 f) the tipmost head specified with the url#branch source syntax
704 f) the tipmost head specified with the url#branch source syntax
705 g) the tipmost head of the default branch
705 g) the tipmost head of the default branch
706 h) tip
706 h) tip
707
707
708 Returns 0 on success.
708 Returns 0 on success.
709 """
709 """
710 if opts.get('noupdate') and opts.get('updaterev'):
710 if opts.get('noupdate') and opts.get('updaterev'):
711 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
711 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
712
712
713 r = hg.clone(hg.remoteui(ui, opts), source, dest,
713 r = hg.clone(hg.remoteui(ui, opts), source, dest,
714 pull=opts.get('pull'),
714 pull=opts.get('pull'),
715 stream=opts.get('uncompressed'),
715 stream=opts.get('uncompressed'),
716 rev=opts.get('rev'),
716 rev=opts.get('rev'),
717 update=opts.get('updaterev') or not opts.get('noupdate'),
717 update=opts.get('updaterev') or not opts.get('noupdate'),
718 branch=opts.get('branch'))
718 branch=opts.get('branch'))
719
719
720 return r is None
720 return r is None
721
721
722 def commit(ui, repo, *pats, **opts):
722 def commit(ui, repo, *pats, **opts):
723 """commit the specified files or all outstanding changes
723 """commit the specified files or all outstanding changes
724
724
725 Commit changes to the given files into the repository. Unlike a
725 Commit changes to the given files into the repository. Unlike a
726 centralized RCS, this operation is a local operation. See
726 centralized RCS, this operation is a local operation. See
727 :hg:`push` for a way to actively distribute your changes.
727 :hg:`push` for a way to actively distribute your changes.
728
728
729 If a list of files is omitted, all changes reported by :hg:`status`
729 If a list of files is omitted, all changes reported by :hg:`status`
730 will be committed.
730 will be committed.
731
731
732 If you are committing the result of a merge, do not provide any
732 If you are committing the result of a merge, do not provide any
733 filenames or -I/-X filters.
733 filenames or -I/-X filters.
734
734
735 If no commit message is specified, Mercurial starts your
735 If no commit message is specified, Mercurial starts your
736 configured editor where you can enter a message. In case your
736 configured editor where you can enter a message. In case your
737 commit fails, you will find a backup of your message in
737 commit fails, you will find a backup of your message in
738 ``.hg/last-message.txt``.
738 ``.hg/last-message.txt``.
739
739
740 See :hg:`help dates` for a list of formats valid for -d/--date.
740 See :hg:`help dates` for a list of formats valid for -d/--date.
741
741
742 Returns 0 on success, 1 if nothing changed.
742 Returns 0 on success, 1 if nothing changed.
743 """
743 """
744 extra = {}
744 extra = {}
745 if opts.get('close_branch'):
745 if opts.get('close_branch'):
746 if repo['.'].node() not in repo.branchheads():
746 if repo['.'].node() not in repo.branchheads():
747 # The topo heads set is included in the branch heads set of the
747 # The topo heads set is included in the branch heads set of the
748 # current branch, so it's sufficient to test branchheads
748 # current branch, so it's sufficient to test branchheads
749 raise util.Abort(_('can only close branch heads'))
749 raise util.Abort(_('can only close branch heads'))
750 extra['close'] = 1
750 extra['close'] = 1
751 e = cmdutil.commiteditor
751 e = cmdutil.commiteditor
752 if opts.get('force_editor'):
752 if opts.get('force_editor'):
753 e = cmdutil.commitforceeditor
753 e = cmdutil.commitforceeditor
754
754
755 def commitfunc(ui, repo, message, match, opts):
755 def commitfunc(ui, repo, message, match, opts):
756 return repo.commit(message, opts.get('user'), opts.get('date'), match,
756 return repo.commit(message, opts.get('user'), opts.get('date'), match,
757 editor=e, extra=extra)
757 editor=e, extra=extra)
758
758
759 branch = repo[None].branch()
759 branch = repo[None].branch()
760 bheads = repo.branchheads(branch)
760 bheads = repo.branchheads(branch)
761
761
762 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
762 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
763 if not node:
763 if not node:
764 ui.status(_("nothing changed\n"))
764 ui.status(_("nothing changed\n"))
765 return 1
765 return 1
766
766
767 ctx = repo[node]
767 ctx = repo[node]
768 parents = ctx.parents()
768 parents = ctx.parents()
769
769
770 if bheads and not [x for x in parents
770 if bheads and not [x for x in parents
771 if x.node() in bheads and x.branch() == branch]:
771 if x.node() in bheads and x.branch() == branch]:
772 ui.status(_('created new head\n'))
772 ui.status(_('created new head\n'))
773 # The message is not printed for initial roots. For the other
773 # The message is not printed for initial roots. For the other
774 # changesets, it is printed in the following situations:
774 # changesets, it is printed in the following situations:
775 #
775 #
776 # Par column: for the 2 parents with ...
776 # Par column: for the 2 parents with ...
777 # N: null or no parent
777 # N: null or no parent
778 # B: parent is on another named branch
778 # B: parent is on another named branch
779 # C: parent is a regular non head changeset
779 # C: parent is a regular non head changeset
780 # H: parent was a branch head of the current branch
780 # H: parent was a branch head of the current branch
781 # Msg column: whether we print "created new head" message
781 # Msg column: whether we print "created new head" message
782 # In the following, it is assumed that there already exists some
782 # In the following, it is assumed that there already exists some
783 # initial branch heads of the current branch, otherwise nothing is
783 # initial branch heads of the current branch, otherwise nothing is
784 # printed anyway.
784 # printed anyway.
785 #
785 #
786 # Par Msg Comment
786 # Par Msg Comment
787 # NN y additional topo root
787 # NN y additional topo root
788 #
788 #
789 # BN y additional branch root
789 # BN y additional branch root
790 # CN y additional topo head
790 # CN y additional topo head
791 # HN n usual case
791 # HN n usual case
792 #
792 #
793 # BB y weird additional branch root
793 # BB y weird additional branch root
794 # CB y branch merge
794 # CB y branch merge
795 # HB n merge with named branch
795 # HB n merge with named branch
796 #
796 #
797 # CC y additional head from merge
797 # CC y additional head from merge
798 # CH n merge with a head
798 # CH n merge with a head
799 #
799 #
800 # HH n head merge: head count decreases
800 # HH n head merge: head count decreases
801
801
802 if not opts.get('close_branch'):
802 if not opts.get('close_branch'):
803 for r in parents:
803 for r in parents:
804 if r.extra().get('close') and r.branch() == branch:
804 if r.extra().get('close') and r.branch() == branch:
805 ui.status(_('reopening closed branch head %d\n') % r)
805 ui.status(_('reopening closed branch head %d\n') % r)
806
806
807 if ui.debugflag:
807 if ui.debugflag:
808 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
808 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
809 elif ui.verbose:
809 elif ui.verbose:
810 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
810 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
811
811
812 def copy(ui, repo, *pats, **opts):
812 def copy(ui, repo, *pats, **opts):
813 """mark files as copied for the next commit
813 """mark files as copied for the next commit
814
814
815 Mark dest as having copies of source files. If dest is a
815 Mark dest as having copies of source files. If dest is a
816 directory, copies are put in that directory. If dest is a file,
816 directory, copies are put in that directory. If dest is a file,
817 the source must be a single file.
817 the source must be a single file.
818
818
819 By default, this command copies the contents of files as they
819 By default, this command copies the contents of files as they
820 exist in the working directory. If invoked with -A/--after, the
820 exist in the working directory. If invoked with -A/--after, the
821 operation is recorded, but no copying is performed.
821 operation is recorded, but no copying is performed.
822
822
823 This command takes effect with the next commit. To undo a copy
823 This command takes effect with the next commit. To undo a copy
824 before that, see :hg:`revert`.
824 before that, see :hg:`revert`.
825
825
826 Returns 0 on success, 1 if errors are encountered.
826 Returns 0 on success, 1 if errors are encountered.
827 """
827 """
828 wlock = repo.wlock(False)
828 wlock = repo.wlock(False)
829 try:
829 try:
830 return cmdutil.copy(ui, repo, pats, opts)
830 return cmdutil.copy(ui, repo, pats, opts)
831 finally:
831 finally:
832 wlock.release()
832 wlock.release()
833
833
834 def debugancestor(ui, repo, *args):
834 def debugancestor(ui, repo, *args):
835 """find the ancestor revision of two revisions in a given index"""
835 """find the ancestor revision of two revisions in a given index"""
836 if len(args) == 3:
836 if len(args) == 3:
837 index, rev1, rev2 = args
837 index, rev1, rev2 = args
838 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
838 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
839 lookup = r.lookup
839 lookup = r.lookup
840 elif len(args) == 2:
840 elif len(args) == 2:
841 if not repo:
841 if not repo:
842 raise util.Abort(_("there is no Mercurial repository here "
842 raise util.Abort(_("there is no Mercurial repository here "
843 "(.hg not found)"))
843 "(.hg not found)"))
844 rev1, rev2 = args
844 rev1, rev2 = args
845 r = repo.changelog
845 r = repo.changelog
846 lookup = repo.lookup
846 lookup = repo.lookup
847 else:
847 else:
848 raise util.Abort(_('either two or three arguments required'))
848 raise util.Abort(_('either two or three arguments required'))
849 a = r.ancestor(lookup(rev1), lookup(rev2))
849 a = r.ancestor(lookup(rev1), lookup(rev2))
850 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
850 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
851
851
852 def debugbuilddag(ui, repo, text,
852 def debugbuilddag(ui, repo, text,
853 mergeable_file=False,
853 mergeable_file=False,
854 appended_file=False,
854 appended_file=False,
855 overwritten_file=False,
855 overwritten_file=False,
856 new_file=False):
856 new_file=False):
857 """builds a repo with a given dag from scratch in the current empty repo
857 """builds a repo with a given dag from scratch in the current empty repo
858
858
859 Elements:
859 Elements:
860
860
861 - "+n" is a linear run of n nodes based on the current default parent
861 - "+n" is a linear run of n nodes based on the current default parent
862 - "." is a single node based on the current default parent
862 - "." is a single node based on the current default parent
863 - "$" resets the default parent to null (implied at the start);
863 - "$" resets the default parent to null (implied at the start);
864 otherwise the default parent is always the last node created
864 otherwise the default parent is always the last node created
865 - "<p" sets the default parent to the backref p
865 - "<p" sets the default parent to the backref p
866 - "*p" is a fork at parent p, which is a backref
866 - "*p" is a fork at parent p, which is a backref
867 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
867 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
868 - "/p2" is a merge of the preceding node and p2
868 - "/p2" is a merge of the preceding node and p2
869 - ":tag" defines a local tag for the preceding node
869 - ":tag" defines a local tag for the preceding node
870 - "@branch" sets the named branch for subsequent nodes
870 - "@branch" sets the named branch for subsequent nodes
871 - "!command" runs the command using your shell
871 - "!command" runs the command using your shell
872 - "!!my command\\n" is like "!", but to the end of the line
872 - "!!my command\\n" is like "!", but to the end of the line
873 - "#...\\n" is a comment up to the end of the line
873 - "#...\\n" is a comment up to the end of the line
874
874
875 Whitespace between the above elements is ignored.
875 Whitespace between the above elements is ignored.
876
876
877 A backref is either
877 A backref is either
878
878
879 - a number n, which references the node curr-n, where curr is the current
879 - a number n, which references the node curr-n, where curr is the current
880 node, or
880 node, or
881 - the name of a local tag you placed earlier using ":tag", or
881 - the name of a local tag you placed earlier using ":tag", or
882 - empty to denote the default parent.
882 - empty to denote the default parent.
883
883
884 All string valued-elements are either strictly alphanumeric, or must
884 All string valued-elements are either strictly alphanumeric, or must
885 be enclosed in double quotes ("..."), with "\\" as escape character.
885 be enclosed in double quotes ("..."), with "\\" as escape character.
886
886
887 Note that the --overwritten-file and --appended-file options imply the
887 Note that the --overwritten-file and --appended-file options imply the
888 use of "HGMERGE=internal:local" during DAG buildup.
888 use of "HGMERGE=internal:local" during DAG buildup.
889 """
889 """
890
890
891 if not (mergeable_file or appended_file or overwritten_file or new_file):
891 if not (mergeable_file or appended_file or overwritten_file or new_file):
892 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
892 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
893
893
894 if len(repo.changelog) > 0:
894 if len(repo.changelog) > 0:
895 raise util.Abort(_('repository is not empty'))
895 raise util.Abort(_('repository is not empty'))
896
896
897 if overwritten_file or appended_file:
897 if overwritten_file or appended_file:
898 # we don't want to fail in merges during buildup
898 # we don't want to fail in merges during buildup
899 os.environ['HGMERGE'] = 'internal:local'
899 os.environ['HGMERGE'] = 'internal:local'
900
900
901 def writefile(fname, text, fmode="wb"):
901 def writefile(fname, text, fmode="wb"):
902 f = open(fname, fmode)
902 f = open(fname, fmode)
903 try:
903 try:
904 f.write(text)
904 f.write(text)
905 finally:
905 finally:
906 f.close()
906 f.close()
907
907
908 if mergeable_file:
908 if mergeable_file:
909 linesperrev = 2
909 linesperrev = 2
910 # determine number of revs in DAG
910 # determine number of revs in DAG
911 n = 0
911 n = 0
912 for type, data in dagparser.parsedag(text):
912 for type, data in dagparser.parsedag(text):
913 if type == 'n':
913 if type == 'n':
914 n += 1
914 n += 1
915 # make a file with k lines per rev
915 # make a file with k lines per rev
916 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
916 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
917 + "\n")
917 + "\n")
918
918
919 at = -1
919 at = -1
920 atbranch = 'default'
920 atbranch = 'default'
921 for type, data in dagparser.parsedag(text):
921 for type, data in dagparser.parsedag(text):
922 if type == 'n':
922 if type == 'n':
923 ui.status('node %s\n' % str(data))
923 ui.status('node %s\n' % str(data))
924 id, ps = data
924 id, ps = data
925 p1 = ps[0]
925 p1 = ps[0]
926 if p1 != at:
926 if p1 != at:
927 update(ui, repo, node=p1, clean=True)
927 update(ui, repo, node=p1, clean=True)
928 at = p1
928 at = p1
929 if repo.dirstate.branch() != atbranch:
929 if repo.dirstate.branch() != atbranch:
930 branch(ui, repo, atbranch, force=True)
930 branch(ui, repo, atbranch, force=True)
931 if len(ps) > 1:
931 if len(ps) > 1:
932 p2 = ps[1]
932 p2 = ps[1]
933 merge(ui, repo, node=p2)
933 merge(ui, repo, node=p2)
934
934
935 if mergeable_file:
935 if mergeable_file:
936 f = open("mf", "rb+")
936 f = open("mf", "rb+")
937 try:
937 try:
938 lines = f.read().split("\n")
938 lines = f.read().split("\n")
939 lines[id * linesperrev] += " r%i" % id
939 lines[id * linesperrev] += " r%i" % id
940 f.seek(0)
940 f.seek(0)
941 f.write("\n".join(lines))
941 f.write("\n".join(lines))
942 finally:
942 finally:
943 f.close()
943 f.close()
944
944
945 if appended_file:
945 if appended_file:
946 writefile("af", "r%i\n" % id, "ab")
946 writefile("af", "r%i\n" % id, "ab")
947
947
948 if overwritten_file:
948 if overwritten_file:
949 writefile("of", "r%i\n" % id)
949 writefile("of", "r%i\n" % id)
950
950
951 if new_file:
951 if new_file:
952 writefile("nf%i" % id, "r%i\n" % id)
952 writefile("nf%i" % id, "r%i\n" % id)
953
953
954 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
954 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
955 at = id
955 at = id
956 elif type == 'l':
956 elif type == 'l':
957 id, name = data
957 id, name = data
958 ui.status('tag %s\n' % name)
958 ui.status('tag %s\n' % name)
959 tag(ui, repo, name, local=True)
959 tag(ui, repo, name, local=True)
960 elif type == 'a':
960 elif type == 'a':
961 ui.status('branch %s\n' % data)
961 ui.status('branch %s\n' % data)
962 atbranch = data
962 atbranch = data
963 elif type in 'cC':
963 elif type in 'cC':
964 r = util.system(data, cwd=repo.root)
964 r = util.system(data, cwd=repo.root)
965 if r:
965 if r:
966 desc, r = util.explain_exit(r)
966 desc, r = util.explain_exit(r)
967 raise util.Abort(_('%s command %s') % (data, desc))
967 raise util.Abort(_('%s command %s') % (data, desc))
968
968
969 def debugcommands(ui, cmd='', *args):
969 def debugcommands(ui, cmd='', *args):
970 """list all available commands and options"""
970 """list all available commands and options"""
971 for cmd, vals in sorted(table.iteritems()):
971 for cmd, vals in sorted(table.iteritems()):
972 cmd = cmd.split('|')[0].strip('^')
972 cmd = cmd.split('|')[0].strip('^')
973 opts = ', '.join([i[1] for i in vals[1]])
973 opts = ', '.join([i[1] for i in vals[1]])
974 ui.write('%s: %s\n' % (cmd, opts))
974 ui.write('%s: %s\n' % (cmd, opts))
975
975
976 def debugcomplete(ui, cmd='', **opts):
976 def debugcomplete(ui, cmd='', **opts):
977 """returns the completion list associated with the given command"""
977 """returns the completion list associated with the given command"""
978
978
979 if opts.get('options'):
979 if opts.get('options'):
980 options = []
980 options = []
981 otables = [globalopts]
981 otables = [globalopts]
982 if cmd:
982 if cmd:
983 aliases, entry = cmdutil.findcmd(cmd, table, False)
983 aliases, entry = cmdutil.findcmd(cmd, table, False)
984 otables.append(entry[1])
984 otables.append(entry[1])
985 for t in otables:
985 for t in otables:
986 for o in t:
986 for o in t:
987 if "(DEPRECATED)" in o[3]:
987 if "(DEPRECATED)" in o[3]:
988 continue
988 continue
989 if o[0]:
989 if o[0]:
990 options.append('-%s' % o[0])
990 options.append('-%s' % o[0])
991 options.append('--%s' % o[1])
991 options.append('--%s' % o[1])
992 ui.write("%s\n" % "\n".join(options))
992 ui.write("%s\n" % "\n".join(options))
993 return
993 return
994
994
995 cmdlist = cmdutil.findpossible(cmd, table)
995 cmdlist = cmdutil.findpossible(cmd, table)
996 if ui.verbose:
996 if ui.verbose:
997 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
997 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
998 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
998 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
999
999
1000 def debugfsinfo(ui, path = "."):
1000 def debugfsinfo(ui, path = "."):
1001 """show information detected about current filesystem"""
1001 """show information detected about current filesystem"""
1002 open('.debugfsinfo', 'w').write('')
1002 open('.debugfsinfo', 'w').write('')
1003 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1003 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1004 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1004 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1005 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1005 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1006 and 'yes' or 'no'))
1006 and 'yes' or 'no'))
1007 os.unlink('.debugfsinfo')
1007 os.unlink('.debugfsinfo')
1008
1008
1009 def debugrebuildstate(ui, repo, rev="tip"):
1009 def debugrebuildstate(ui, repo, rev="tip"):
1010 """rebuild the dirstate as it would look like for the given revision"""
1010 """rebuild the dirstate as it would look like for the given revision"""
1011 ctx = repo[rev]
1011 ctx = repo[rev]
1012 wlock = repo.wlock()
1012 wlock = repo.wlock()
1013 try:
1013 try:
1014 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1014 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1015 finally:
1015 finally:
1016 wlock.release()
1016 wlock.release()
1017
1017
1018 def debugcheckstate(ui, repo):
1018 def debugcheckstate(ui, repo):
1019 """validate the correctness of the current dirstate"""
1019 """validate the correctness of the current dirstate"""
1020 parent1, parent2 = repo.dirstate.parents()
1020 parent1, parent2 = repo.dirstate.parents()
1021 m1 = repo[parent1].manifest()
1021 m1 = repo[parent1].manifest()
1022 m2 = repo[parent2].manifest()
1022 m2 = repo[parent2].manifest()
1023 errors = 0
1023 errors = 0
1024 for f in repo.dirstate:
1024 for f in repo.dirstate:
1025 state = repo.dirstate[f]
1025 state = repo.dirstate[f]
1026 if state in "nr" and f not in m1:
1026 if state in "nr" and f not in m1:
1027 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1027 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1028 errors += 1
1028 errors += 1
1029 if state in "a" and f in m1:
1029 if state in "a" and f in m1:
1030 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1030 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1031 errors += 1
1031 errors += 1
1032 if state in "m" and f not in m1 and f not in m2:
1032 if state in "m" and f not in m1 and f not in m2:
1033 ui.warn(_("%s in state %s, but not in either manifest\n") %
1033 ui.warn(_("%s in state %s, but not in either manifest\n") %
1034 (f, state))
1034 (f, state))
1035 errors += 1
1035 errors += 1
1036 for f in m1:
1036 for f in m1:
1037 state = repo.dirstate[f]
1037 state = repo.dirstate[f]
1038 if state not in "nrm":
1038 if state not in "nrm":
1039 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1039 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1040 errors += 1
1040 errors += 1
1041 if errors:
1041 if errors:
1042 error = _(".hg/dirstate inconsistent with current parent's manifest")
1042 error = _(".hg/dirstate inconsistent with current parent's manifest")
1043 raise util.Abort(error)
1043 raise util.Abort(error)
1044
1044
1045 def showconfig(ui, repo, *values, **opts):
1045 def showconfig(ui, repo, *values, **opts):
1046 """show combined config settings from all hgrc files
1046 """show combined config settings from all hgrc files
1047
1047
1048 With no arguments, print names and values of all config items.
1048 With no arguments, print names and values of all config items.
1049
1049
1050 With one argument of the form section.name, print just the value
1050 With one argument of the form section.name, print just the value
1051 of that config item.
1051 of that config item.
1052
1052
1053 With multiple arguments, print names and values of all config
1053 With multiple arguments, print names and values of all config
1054 items with matching section names.
1054 items with matching section names.
1055
1055
1056 With --debug, the source (filename and line number) is printed
1056 With --debug, the source (filename and line number) is printed
1057 for each config item.
1057 for each config item.
1058
1058
1059 Returns 0 on success.
1059 Returns 0 on success.
1060 """
1060 """
1061
1061
1062 for f in util.rcpath():
1062 for f in util.rcpath():
1063 ui.debug(_('read config from: %s\n') % f)
1063 ui.debug(_('read config from: %s\n') % f)
1064 untrusted = bool(opts.get('untrusted'))
1064 untrusted = bool(opts.get('untrusted'))
1065 if values:
1065 if values:
1066 if len([v for v in values if '.' in v]) > 1:
1066 if len([v for v in values if '.' in v]) > 1:
1067 raise util.Abort(_('only one config item permitted'))
1067 raise util.Abort(_('only one config item permitted'))
1068 for section, name, value in ui.walkconfig(untrusted=untrusted):
1068 for section, name, value in ui.walkconfig(untrusted=untrusted):
1069 sectname = section + '.' + name
1069 sectname = section + '.' + name
1070 if values:
1070 if values:
1071 for v in values:
1071 for v in values:
1072 if v == section:
1072 if v == section:
1073 ui.debug('%s: ' %
1073 ui.debug('%s: ' %
1074 ui.configsource(section, name, untrusted))
1074 ui.configsource(section, name, untrusted))
1075 ui.write('%s=%s\n' % (sectname, value))
1075 ui.write('%s=%s\n' % (sectname, value))
1076 elif v == sectname:
1076 elif v == sectname:
1077 ui.debug('%s: ' %
1077 ui.debug('%s: ' %
1078 ui.configsource(section, name, untrusted))
1078 ui.configsource(section, name, untrusted))
1079 ui.write(value, '\n')
1079 ui.write(value, '\n')
1080 else:
1080 else:
1081 ui.debug('%s: ' %
1081 ui.debug('%s: ' %
1082 ui.configsource(section, name, untrusted))
1082 ui.configsource(section, name, untrusted))
1083 ui.write('%s=%s\n' % (sectname, value))
1083 ui.write('%s=%s\n' % (sectname, value))
1084
1084
1085 def debugpushkey(ui, repopath, namespace, *keyinfo):
1085 def debugpushkey(ui, repopath, namespace, *keyinfo):
1086 '''access the pushkey key/value protocol
1086 '''access the pushkey key/value protocol
1087
1087
1088 With two args, list the keys in the given namespace.
1088 With two args, list the keys in the given namespace.
1089
1089
1090 With five args, set a key to new if it currently is set to old.
1090 With five args, set a key to new if it currently is set to old.
1091 Reports success or failure.
1091 Reports success or failure.
1092 '''
1092 '''
1093
1093
1094 target = hg.repository(ui, repopath)
1094 target = hg.repository(ui, repopath)
1095 if keyinfo:
1095 if keyinfo:
1096 key, old, new = keyinfo
1096 key, old, new = keyinfo
1097 r = target.pushkey(namespace, key, old, new)
1097 r = target.pushkey(namespace, key, old, new)
1098 ui.status(str(r) + '\n')
1098 ui.status(str(r) + '\n')
1099 return not(r)
1099 return not(r)
1100 else:
1100 else:
1101 for k, v in target.listkeys(namespace).iteritems():
1101 for k, v in target.listkeys(namespace).iteritems():
1102 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1102 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1103 v.encode('string-escape')))
1103 v.encode('string-escape')))
1104
1104
1105 def debugrevspec(ui, repo, expr):
1105 def debugrevspec(ui, repo, expr):
1106 '''parse and apply a revision specification'''
1106 '''parse and apply a revision specification'''
1107 if ui.verbose:
1107 if ui.verbose:
1108 tree = revset.parse(expr)
1108 tree = revset.parse(expr)
1109 ui.note(tree, "\n")
1109 ui.note(tree, "\n")
1110 func = revset.match(expr)
1110 func = revset.match(expr)
1111 for c in func(repo, range(len(repo))):
1111 for c in func(repo, range(len(repo))):
1112 ui.write("%s\n" % c)
1112 ui.write("%s\n" % c)
1113
1113
1114 def debugsetparents(ui, repo, rev1, rev2=None):
1114 def debugsetparents(ui, repo, rev1, rev2=None):
1115 """manually set the parents of the current working directory
1115 """manually set the parents of the current working directory
1116
1116
1117 This is useful for writing repository conversion tools, but should
1117 This is useful for writing repository conversion tools, but should
1118 be used with care.
1118 be used with care.
1119
1119
1120 Returns 0 on success.
1120 Returns 0 on success.
1121 """
1121 """
1122
1122
1123 if not rev2:
1123 if not rev2:
1124 rev2 = hex(nullid)
1124 rev2 = hex(nullid)
1125
1125
1126 wlock = repo.wlock()
1126 wlock = repo.wlock()
1127 try:
1127 try:
1128 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1128 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1129 finally:
1129 finally:
1130 wlock.release()
1130 wlock.release()
1131
1131
1132 def debugstate(ui, repo, nodates=None):
1132 def debugstate(ui, repo, nodates=None):
1133 """show the contents of the current dirstate"""
1133 """show the contents of the current dirstate"""
1134 timestr = ""
1134 timestr = ""
1135 showdate = not nodates
1135 showdate = not nodates
1136 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1136 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1137 if showdate:
1137 if showdate:
1138 if ent[3] == -1:
1138 if ent[3] == -1:
1139 # Pad or slice to locale representation
1139 # Pad or slice to locale representation
1140 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1140 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1141 time.localtime(0)))
1141 time.localtime(0)))
1142 timestr = 'unset'
1142 timestr = 'unset'
1143 timestr = (timestr[:locale_len] +
1143 timestr = (timestr[:locale_len] +
1144 ' ' * (locale_len - len(timestr)))
1144 ' ' * (locale_len - len(timestr)))
1145 else:
1145 else:
1146 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1146 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1147 time.localtime(ent[3]))
1147 time.localtime(ent[3]))
1148 if ent[1] & 020000:
1148 if ent[1] & 020000:
1149 mode = 'lnk'
1149 mode = 'lnk'
1150 else:
1150 else:
1151 mode = '%3o' % (ent[1] & 0777)
1151 mode = '%3o' % (ent[1] & 0777)
1152 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1152 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1153 for f in repo.dirstate.copies():
1153 for f in repo.dirstate.copies():
1154 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1154 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1155
1155
1156 def debugsub(ui, repo, rev=None):
1156 def debugsub(ui, repo, rev=None):
1157 if rev == '':
1157 if rev == '':
1158 rev = None
1158 rev = None
1159 for k, v in sorted(repo[rev].substate.items()):
1159 for k, v in sorted(repo[rev].substate.items()):
1160 ui.write('path %s\n' % k)
1160 ui.write('path %s\n' % k)
1161 ui.write(' source %s\n' % v[0])
1161 ui.write(' source %s\n' % v[0])
1162 ui.write(' revision %s\n' % v[1])
1162 ui.write(' revision %s\n' % v[1])
1163
1163
1164 def debugdag(ui, repo, file_=None, *revs, **opts):
1164 def debugdag(ui, repo, file_=None, *revs, **opts):
1165 """format the changelog or an index DAG as a concise textual description
1165 """format the changelog or an index DAG as a concise textual description
1166
1166
1167 If you pass a revlog index, the revlog's DAG is emitted. If you list
1167 If you pass a revlog index, the revlog's DAG is emitted. If you list
1168 revision numbers, they get labelled in the output as rN.
1168 revision numbers, they get labelled in the output as rN.
1169
1169
1170 Otherwise, the changelog DAG of the current repo is emitted.
1170 Otherwise, the changelog DAG of the current repo is emitted.
1171 """
1171 """
1172 spaces = opts.get('spaces')
1172 spaces = opts.get('spaces')
1173 dots = opts.get('dots')
1173 dots = opts.get('dots')
1174 if file_:
1174 if file_:
1175 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1175 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1176 revs = set((int(r) for r in revs))
1176 revs = set((int(r) for r in revs))
1177 def events():
1177 def events():
1178 for r in rlog:
1178 for r in rlog:
1179 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1179 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1180 if r in revs:
1180 if r in revs:
1181 yield 'l', (r, "r%i" % r)
1181 yield 'l', (r, "r%i" % r)
1182 elif repo:
1182 elif repo:
1183 cl = repo.changelog
1183 cl = repo.changelog
1184 tags = opts.get('tags')
1184 tags = opts.get('tags')
1185 branches = opts.get('branches')
1185 branches = opts.get('branches')
1186 if tags:
1186 if tags:
1187 labels = {}
1187 labels = {}
1188 for l, n in repo.tags().items():
1188 for l, n in repo.tags().items():
1189 labels.setdefault(cl.rev(n), []).append(l)
1189 labels.setdefault(cl.rev(n), []).append(l)
1190 def events():
1190 def events():
1191 b = "default"
1191 b = "default"
1192 for r in cl:
1192 for r in cl:
1193 if branches:
1193 if branches:
1194 newb = cl.read(cl.node(r))[5]['branch']
1194 newb = cl.read(cl.node(r))[5]['branch']
1195 if newb != b:
1195 if newb != b:
1196 yield 'a', newb
1196 yield 'a', newb
1197 b = newb
1197 b = newb
1198 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1198 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1199 if tags:
1199 if tags:
1200 ls = labels.get(r)
1200 ls = labels.get(r)
1201 if ls:
1201 if ls:
1202 for l in ls:
1202 for l in ls:
1203 yield 'l', (r, l)
1203 yield 'l', (r, l)
1204 else:
1204 else:
1205 raise util.Abort(_('need repo for changelog dag'))
1205 raise util.Abort(_('need repo for changelog dag'))
1206
1206
1207 for line in dagparser.dagtextlines(events(),
1207 for line in dagparser.dagtextlines(events(),
1208 addspaces=spaces,
1208 addspaces=spaces,
1209 wraplabels=True,
1209 wraplabels=True,
1210 wrapannotations=True,
1210 wrapannotations=True,
1211 wrapnonlinear=dots,
1211 wrapnonlinear=dots,
1212 usedots=dots,
1212 usedots=dots,
1213 maxlinewidth=70):
1213 maxlinewidth=70):
1214 ui.write(line)
1214 ui.write(line)
1215 ui.write("\n")
1215 ui.write("\n")
1216
1216
1217 def debugdata(ui, file_, rev):
1217 def debugdata(ui, file_, rev):
1218 """dump the contents of a data file revision"""
1218 """dump the contents of a data file revision"""
1219 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1219 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1220 try:
1220 try:
1221 ui.write(r.revision(r.lookup(rev)))
1221 ui.write(r.revision(r.lookup(rev)))
1222 except KeyError:
1222 except KeyError:
1223 raise util.Abort(_('invalid revision identifier %s') % rev)
1223 raise util.Abort(_('invalid revision identifier %s') % rev)
1224
1224
1225 def debugdate(ui, date, range=None, **opts):
1225 def debugdate(ui, date, range=None, **opts):
1226 """parse and display a date"""
1226 """parse and display a date"""
1227 if opts["extended"]:
1227 if opts["extended"]:
1228 d = util.parsedate(date, util.extendeddateformats)
1228 d = util.parsedate(date, util.extendeddateformats)
1229 else:
1229 else:
1230 d = util.parsedate(date)
1230 d = util.parsedate(date)
1231 ui.write("internal: %s %s\n" % d)
1231 ui.write("internal: %s %s\n" % d)
1232 ui.write("standard: %s\n" % util.datestr(d))
1232 ui.write("standard: %s\n" % util.datestr(d))
1233 if range:
1233 if range:
1234 m = util.matchdate(range)
1234 m = util.matchdate(range)
1235 ui.write("match: %s\n" % m(d[0]))
1235 ui.write("match: %s\n" % m(d[0]))
1236
1236
1237 def debugindex(ui, file_):
1237 def debugindex(ui, file_):
1238 """dump the contents of an index file"""
1238 """dump the contents of an index file"""
1239 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1239 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1240 ui.write(" rev offset length base linkrev"
1240 ui.write(" rev offset length base linkrev"
1241 " nodeid p1 p2\n")
1241 " nodeid p1 p2\n")
1242 for i in r:
1242 for i in r:
1243 node = r.node(i)
1243 node = r.node(i)
1244 try:
1244 try:
1245 pp = r.parents(node)
1245 pp = r.parents(node)
1246 except:
1246 except:
1247 pp = [nullid, nullid]
1247 pp = [nullid, nullid]
1248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1249 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1249 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1250 short(node), short(pp[0]), short(pp[1])))
1250 short(node), short(pp[0]), short(pp[1])))
1251
1251
1252 def debugindexdot(ui, file_):
1252 def debugindexdot(ui, file_):
1253 """dump an index DAG as a graphviz dot file"""
1253 """dump an index DAG as a graphviz dot file"""
1254 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1254 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1255 ui.write("digraph G {\n")
1255 ui.write("digraph G {\n")
1256 for i in r:
1256 for i in r:
1257 node = r.node(i)
1257 node = r.node(i)
1258 pp = r.parents(node)
1258 pp = r.parents(node)
1259 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1259 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1260 if pp[1] != nullid:
1260 if pp[1] != nullid:
1261 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1261 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1262 ui.write("}\n")
1262 ui.write("}\n")
1263
1263
1264 def debuginstall(ui):
1264 def debuginstall(ui):
1265 '''test Mercurial installation
1265 '''test Mercurial installation
1266
1266
1267 Returns 0 on success.
1267 Returns 0 on success.
1268 '''
1268 '''
1269
1269
1270 def writetemp(contents):
1270 def writetemp(contents):
1271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1272 f = os.fdopen(fd, "wb")
1272 f = os.fdopen(fd, "wb")
1273 f.write(contents)
1273 f.write(contents)
1274 f.close()
1274 f.close()
1275 return name
1275 return name
1276
1276
1277 problems = 0
1277 problems = 0
1278
1278
1279 # encoding
1279 # encoding
1280 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1280 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1281 try:
1281 try:
1282 encoding.fromlocal("test")
1282 encoding.fromlocal("test")
1283 except util.Abort, inst:
1283 except util.Abort, inst:
1284 ui.write(" %s\n" % inst)
1284 ui.write(" %s\n" % inst)
1285 ui.write(_(" (check that your locale is properly set)\n"))
1285 ui.write(_(" (check that your locale is properly set)\n"))
1286 problems += 1
1286 problems += 1
1287
1287
1288 # compiled modules
1288 # compiled modules
1289 ui.status(_("Checking installed modules (%s)...\n")
1289 ui.status(_("Checking installed modules (%s)...\n")
1290 % os.path.dirname(__file__))
1290 % os.path.dirname(__file__))
1291 try:
1291 try:
1292 import bdiff, mpatch, base85, osutil
1292 import bdiff, mpatch, base85, osutil
1293 except Exception, inst:
1293 except Exception, inst:
1294 ui.write(" %s\n" % inst)
1294 ui.write(" %s\n" % inst)
1295 ui.write(_(" One or more extensions could not be found"))
1295 ui.write(_(" One or more extensions could not be found"))
1296 ui.write(_(" (check that you compiled the extensions)\n"))
1296 ui.write(_(" (check that you compiled the extensions)\n"))
1297 problems += 1
1297 problems += 1
1298
1298
1299 # templates
1299 # templates
1300 ui.status(_("Checking templates...\n"))
1300 ui.status(_("Checking templates...\n"))
1301 try:
1301 try:
1302 import templater
1302 import templater
1303 templater.templater(templater.templatepath("map-cmdline.default"))
1303 templater.templater(templater.templatepath("map-cmdline.default"))
1304 except Exception, inst:
1304 except Exception, inst:
1305 ui.write(" %s\n" % inst)
1305 ui.write(" %s\n" % inst)
1306 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1306 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1307 problems += 1
1307 problems += 1
1308
1308
1309 # patch
1309 # patch
1310 ui.status(_("Checking patch...\n"))
1310 ui.status(_("Checking patch...\n"))
1311 patchproblems = 0
1311 patchproblems = 0
1312 a = "1\n2\n3\n4\n"
1312 a = "1\n2\n3\n4\n"
1313 b = "1\n2\n3\ninsert\n4\n"
1313 b = "1\n2\n3\ninsert\n4\n"
1314 fa = writetemp(a)
1314 fa = writetemp(a)
1315 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1315 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1316 os.path.basename(fa))
1316 os.path.basename(fa))
1317 fd = writetemp(d)
1317 fd = writetemp(d)
1318
1318
1319 files = {}
1319 files = {}
1320 try:
1320 try:
1321 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1321 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1322 except util.Abort, e:
1322 except util.Abort, e:
1323 ui.write(_(" patch call failed:\n"))
1323 ui.write(_(" patch call failed:\n"))
1324 ui.write(" " + str(e) + "\n")
1324 ui.write(" " + str(e) + "\n")
1325 patchproblems += 1
1325 patchproblems += 1
1326 else:
1326 else:
1327 if list(files) != [os.path.basename(fa)]:
1327 if list(files) != [os.path.basename(fa)]:
1328 ui.write(_(" unexpected patch output!\n"))
1328 ui.write(_(" unexpected patch output!\n"))
1329 patchproblems += 1
1329 patchproblems += 1
1330 a = open(fa).read()
1330 a = open(fa).read()
1331 if a != b:
1331 if a != b:
1332 ui.write(_(" patch test failed!\n"))
1332 ui.write(_(" patch test failed!\n"))
1333 patchproblems += 1
1333 patchproblems += 1
1334
1334
1335 if patchproblems:
1335 if patchproblems:
1336 if ui.config('ui', 'patch'):
1336 if ui.config('ui', 'patch'):
1337 ui.write(_(" (Current patch tool may be incompatible with patch,"
1337 ui.write(_(" (Current patch tool may be incompatible with patch,"
1338 " or misconfigured. Please check your .hgrc file)\n"))
1338 " or misconfigured. Please check your configuration"
1339 " file)\n"))
1339 else:
1340 else:
1340 ui.write(_(" Internal patcher failure, please report this error"
1341 ui.write(_(" Internal patcher failure, please report this error"
1341 " to http://mercurial.selenic.com/bts/\n"))
1342 " to http://mercurial.selenic.com/bts/\n"))
1342 problems += patchproblems
1343 problems += patchproblems
1343
1344
1344 os.unlink(fa)
1345 os.unlink(fa)
1345 os.unlink(fd)
1346 os.unlink(fd)
1346
1347
1347 # editor
1348 # editor
1348 ui.status(_("Checking commit editor...\n"))
1349 ui.status(_("Checking commit editor...\n"))
1349 editor = ui.geteditor()
1350 editor = ui.geteditor()
1350 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1351 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1351 if not cmdpath:
1352 if not cmdpath:
1352 if editor == 'vi':
1353 if editor == 'vi':
1353 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1354 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1354 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1355 ui.write(_(" (specify a commit editor in your configuration"
1356 " file)\n"))
1355 else:
1357 else:
1356 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1358 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1357 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1359 ui.write(_(" (specify a commit editor in your configuration"
1360 " file)\n"))
1358 problems += 1
1361 problems += 1
1359
1362
1360 # check username
1363 # check username
1361 ui.status(_("Checking username...\n"))
1364 ui.status(_("Checking username...\n"))
1362 try:
1365 try:
1363 ui.username()
1366 ui.username()
1364 except util.Abort, e:
1367 except util.Abort, e:
1365 ui.write(" %s\n" % e)
1368 ui.write(" %s\n" % e)
1366 ui.write(_(" (specify a username in your .hgrc file)\n"))
1369 ui.write(_(" (specify a username in your configuration file)\n"))
1367 problems += 1
1370 problems += 1
1368
1371
1369 if not problems:
1372 if not problems:
1370 ui.status(_("No problems detected\n"))
1373 ui.status(_("No problems detected\n"))
1371 else:
1374 else:
1372 ui.write(_("%s problems detected,"
1375 ui.write(_("%s problems detected,"
1373 " please check your install!\n") % problems)
1376 " please check your install!\n") % problems)
1374
1377
1375 return problems
1378 return problems
1376
1379
1377 def debugrename(ui, repo, file1, *pats, **opts):
1380 def debugrename(ui, repo, file1, *pats, **opts):
1378 """dump rename information"""
1381 """dump rename information"""
1379
1382
1380 ctx = repo[opts.get('rev')]
1383 ctx = repo[opts.get('rev')]
1381 m = cmdutil.match(repo, (file1,) + pats, opts)
1384 m = cmdutil.match(repo, (file1,) + pats, opts)
1382 for abs in ctx.walk(m):
1385 for abs in ctx.walk(m):
1383 fctx = ctx[abs]
1386 fctx = ctx[abs]
1384 o = fctx.filelog().renamed(fctx.filenode())
1387 o = fctx.filelog().renamed(fctx.filenode())
1385 rel = m.rel(abs)
1388 rel = m.rel(abs)
1386 if o:
1389 if o:
1387 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1390 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1388 else:
1391 else:
1389 ui.write(_("%s not renamed\n") % rel)
1392 ui.write(_("%s not renamed\n") % rel)
1390
1393
1391 def debugwalk(ui, repo, *pats, **opts):
1394 def debugwalk(ui, repo, *pats, **opts):
1392 """show how files match on given patterns"""
1395 """show how files match on given patterns"""
1393 m = cmdutil.match(repo, pats, opts)
1396 m = cmdutil.match(repo, pats, opts)
1394 items = list(repo.walk(m))
1397 items = list(repo.walk(m))
1395 if not items:
1398 if not items:
1396 return
1399 return
1397 fmt = 'f %%-%ds %%-%ds %%s' % (
1400 fmt = 'f %%-%ds %%-%ds %%s' % (
1398 max([len(abs) for abs in items]),
1401 max([len(abs) for abs in items]),
1399 max([len(m.rel(abs)) for abs in items]))
1402 max([len(m.rel(abs)) for abs in items]))
1400 for abs in items:
1403 for abs in items:
1401 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1404 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1402 ui.write("%s\n" % line.rstrip())
1405 ui.write("%s\n" % line.rstrip())
1403
1406
1404 def diff(ui, repo, *pats, **opts):
1407 def diff(ui, repo, *pats, **opts):
1405 """diff repository (or selected files)
1408 """diff repository (or selected files)
1406
1409
1407 Show differences between revisions for the specified files.
1410 Show differences between revisions for the specified files.
1408
1411
1409 Differences between files are shown using the unified diff format.
1412 Differences between files are shown using the unified diff format.
1410
1413
1411 NOTE: diff may generate unexpected results for merges, as it will
1414 NOTE: diff may generate unexpected results for merges, as it will
1412 default to comparing against the working directory's first parent
1415 default to comparing against the working directory's first parent
1413 changeset if no revisions are specified.
1416 changeset if no revisions are specified.
1414
1417
1415 When two revision arguments are given, then changes are shown
1418 When two revision arguments are given, then changes are shown
1416 between those revisions. If only one revision is specified then
1419 between those revisions. If only one revision is specified then
1417 that revision is compared to the working directory, and, when no
1420 that revision is compared to the working directory, and, when no
1418 revisions are specified, the working directory files are compared
1421 revisions are specified, the working directory files are compared
1419 to its parent.
1422 to its parent.
1420
1423
1421 Alternatively you can specify -c/--change with a revision to see
1424 Alternatively you can specify -c/--change with a revision to see
1422 the changes in that changeset relative to its first parent.
1425 the changes in that changeset relative to its first parent.
1423
1426
1424 Without the -a/--text option, diff will avoid generating diffs of
1427 Without the -a/--text option, diff will avoid generating diffs of
1425 files it detects as binary. With -a, diff will generate a diff
1428 files it detects as binary. With -a, diff will generate a diff
1426 anyway, probably with undesirable results.
1429 anyway, probably with undesirable results.
1427
1430
1428 Use the -g/--git option to generate diffs in the git extended diff
1431 Use the -g/--git option to generate diffs in the git extended diff
1429 format. For more information, read :hg:`help diffs`.
1432 format. For more information, read :hg:`help diffs`.
1430
1433
1431 Returns 0 on success.
1434 Returns 0 on success.
1432 """
1435 """
1433
1436
1434 revs = opts.get('rev')
1437 revs = opts.get('rev')
1435 change = opts.get('change')
1438 change = opts.get('change')
1436 stat = opts.get('stat')
1439 stat = opts.get('stat')
1437 reverse = opts.get('reverse')
1440 reverse = opts.get('reverse')
1438
1441
1439 if revs and change:
1442 if revs and change:
1440 msg = _('cannot specify --rev and --change at the same time')
1443 msg = _('cannot specify --rev and --change at the same time')
1441 raise util.Abort(msg)
1444 raise util.Abort(msg)
1442 elif change:
1445 elif change:
1443 node2 = repo.lookup(change)
1446 node2 = repo.lookup(change)
1444 node1 = repo[node2].parents()[0].node()
1447 node1 = repo[node2].parents()[0].node()
1445 else:
1448 else:
1446 node1, node2 = cmdutil.revpair(repo, revs)
1449 node1, node2 = cmdutil.revpair(repo, revs)
1447
1450
1448 if reverse:
1451 if reverse:
1449 node1, node2 = node2, node1
1452 node1, node2 = node2, node1
1450
1453
1451 diffopts = patch.diffopts(ui, opts)
1454 diffopts = patch.diffopts(ui, opts)
1452 m = cmdutil.match(repo, pats, opts)
1455 m = cmdutil.match(repo, pats, opts)
1453 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat)
1456 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat)
1454
1457
1455 def export(ui, repo, *changesets, **opts):
1458 def export(ui, repo, *changesets, **opts):
1456 """dump the header and diffs for one or more changesets
1459 """dump the header and diffs for one or more changesets
1457
1460
1458 Print the changeset header and diffs for one or more revisions.
1461 Print the changeset header and diffs for one or more revisions.
1459
1462
1460 The information shown in the changeset header is: author, date,
1463 The information shown in the changeset header is: author, date,
1461 branch name (if non-default), changeset hash, parent(s) and commit
1464 branch name (if non-default), changeset hash, parent(s) and commit
1462 comment.
1465 comment.
1463
1466
1464 NOTE: export may generate unexpected diff output for merge
1467 NOTE: export may generate unexpected diff output for merge
1465 changesets, as it will compare the merge changeset against its
1468 changesets, as it will compare the merge changeset against its
1466 first parent only.
1469 first parent only.
1467
1470
1468 Output may be to a file, in which case the name of the file is
1471 Output may be to a file, in which case the name of the file is
1469 given using a format string. The formatting rules are as follows:
1472 given using a format string. The formatting rules are as follows:
1470
1473
1471 :``%%``: literal "%" character
1474 :``%%``: literal "%" character
1472 :``%H``: changeset hash (40 hexadecimal digits)
1475 :``%H``: changeset hash (40 hexadecimal digits)
1473 :``%N``: number of patches being generated
1476 :``%N``: number of patches being generated
1474 :``%R``: changeset revision number
1477 :``%R``: changeset revision number
1475 :``%b``: basename of the exporting repository
1478 :``%b``: basename of the exporting repository
1476 :``%h``: short-form changeset hash (12 hexadecimal digits)
1479 :``%h``: short-form changeset hash (12 hexadecimal digits)
1477 :``%n``: zero-padded sequence number, starting at 1
1480 :``%n``: zero-padded sequence number, starting at 1
1478 :``%r``: zero-padded changeset revision number
1481 :``%r``: zero-padded changeset revision number
1479
1482
1480 Without the -a/--text option, export will avoid generating diffs
1483 Without the -a/--text option, export will avoid generating diffs
1481 of files it detects as binary. With -a, export will generate a
1484 of files it detects as binary. With -a, export will generate a
1482 diff anyway, probably with undesirable results.
1485 diff anyway, probably with undesirable results.
1483
1486
1484 Use the -g/--git option to generate diffs in the git extended diff
1487 Use the -g/--git option to generate diffs in the git extended diff
1485 format. See :hg:`help diffs` for more information.
1488 format. See :hg:`help diffs` for more information.
1486
1489
1487 With the --switch-parent option, the diff will be against the
1490 With the --switch-parent option, the diff will be against the
1488 second parent. It can be useful to review a merge.
1491 second parent. It can be useful to review a merge.
1489
1492
1490 Returns 0 on success.
1493 Returns 0 on success.
1491 """
1494 """
1492 changesets += tuple(opts.get('rev', []))
1495 changesets += tuple(opts.get('rev', []))
1493 if not changesets:
1496 if not changesets:
1494 raise util.Abort(_("export requires at least one changeset"))
1497 raise util.Abort(_("export requires at least one changeset"))
1495 revs = cmdutil.revrange(repo, changesets)
1498 revs = cmdutil.revrange(repo, changesets)
1496 if len(revs) > 1:
1499 if len(revs) > 1:
1497 ui.note(_('exporting patches:\n'))
1500 ui.note(_('exporting patches:\n'))
1498 else:
1501 else:
1499 ui.note(_('exporting patch:\n'))
1502 ui.note(_('exporting patch:\n'))
1500 cmdutil.export(repo, revs, template=opts.get('output'),
1503 cmdutil.export(repo, revs, template=opts.get('output'),
1501 switch_parent=opts.get('switch_parent'),
1504 switch_parent=opts.get('switch_parent'),
1502 opts=patch.diffopts(ui, opts))
1505 opts=patch.diffopts(ui, opts))
1503
1506
1504 def forget(ui, repo, *pats, **opts):
1507 def forget(ui, repo, *pats, **opts):
1505 """forget the specified files on the next commit
1508 """forget the specified files on the next commit
1506
1509
1507 Mark the specified files so they will no longer be tracked
1510 Mark the specified files so they will no longer be tracked
1508 after the next commit.
1511 after the next commit.
1509
1512
1510 This only removes files from the current branch, not from the
1513 This only removes files from the current branch, not from the
1511 entire project history, and it does not delete them from the
1514 entire project history, and it does not delete them from the
1512 working directory.
1515 working directory.
1513
1516
1514 To undo a forget before the next commit, see :hg:`add`.
1517 To undo a forget before the next commit, see :hg:`add`.
1515
1518
1516 Returns 0 on success.
1519 Returns 0 on success.
1517 """
1520 """
1518
1521
1519 if not pats:
1522 if not pats:
1520 raise util.Abort(_('no files specified'))
1523 raise util.Abort(_('no files specified'))
1521
1524
1522 m = cmdutil.match(repo, pats, opts)
1525 m = cmdutil.match(repo, pats, opts)
1523 s = repo.status(match=m, clean=True)
1526 s = repo.status(match=m, clean=True)
1524 forget = sorted(s[0] + s[1] + s[3] + s[6])
1527 forget = sorted(s[0] + s[1] + s[3] + s[6])
1525 errs = 0
1528 errs = 0
1526
1529
1527 for f in m.files():
1530 for f in m.files():
1528 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1531 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1529 ui.warn(_('not removing %s: file is already untracked\n')
1532 ui.warn(_('not removing %s: file is already untracked\n')
1530 % m.rel(f))
1533 % m.rel(f))
1531 errs = 1
1534 errs = 1
1532
1535
1533 for f in forget:
1536 for f in forget:
1534 if ui.verbose or not m.exact(f):
1537 if ui.verbose or not m.exact(f):
1535 ui.status(_('removing %s\n') % m.rel(f))
1538 ui.status(_('removing %s\n') % m.rel(f))
1536
1539
1537 repo[None].remove(forget, unlink=False)
1540 repo[None].remove(forget, unlink=False)
1538 return errs
1541 return errs
1539
1542
1540 def grep(ui, repo, pattern, *pats, **opts):
1543 def grep(ui, repo, pattern, *pats, **opts):
1541 """search for a pattern in specified files and revisions
1544 """search for a pattern in specified files and revisions
1542
1545
1543 Search revisions of files for a regular expression.
1546 Search revisions of files for a regular expression.
1544
1547
1545 This command behaves differently than Unix grep. It only accepts
1548 This command behaves differently than Unix grep. It only accepts
1546 Python/Perl regexps. It searches repository history, not the
1549 Python/Perl regexps. It searches repository history, not the
1547 working directory. It always prints the revision number in which a
1550 working directory. It always prints the revision number in which a
1548 match appears.
1551 match appears.
1549
1552
1550 By default, grep only prints output for the first revision of a
1553 By default, grep only prints output for the first revision of a
1551 file in which it finds a match. To get it to print every revision
1554 file in which it finds a match. To get it to print every revision
1552 that contains a change in match status ("-" for a match that
1555 that contains a change in match status ("-" for a match that
1553 becomes a non-match, or "+" for a non-match that becomes a match),
1556 becomes a non-match, or "+" for a non-match that becomes a match),
1554 use the --all flag.
1557 use the --all flag.
1555
1558
1556 Returns 0 if a match is found, 1 otherwise.
1559 Returns 0 if a match is found, 1 otherwise.
1557 """
1560 """
1558 reflags = 0
1561 reflags = 0
1559 if opts.get('ignore_case'):
1562 if opts.get('ignore_case'):
1560 reflags |= re.I
1563 reflags |= re.I
1561 try:
1564 try:
1562 regexp = re.compile(pattern, reflags)
1565 regexp = re.compile(pattern, reflags)
1563 except Exception, inst:
1566 except Exception, inst:
1564 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1567 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1565 return 1
1568 return 1
1566 sep, eol = ':', '\n'
1569 sep, eol = ':', '\n'
1567 if opts.get('print0'):
1570 if opts.get('print0'):
1568 sep = eol = '\0'
1571 sep = eol = '\0'
1569
1572
1570 getfile = util.lrucachefunc(repo.file)
1573 getfile = util.lrucachefunc(repo.file)
1571
1574
1572 def matchlines(body):
1575 def matchlines(body):
1573 begin = 0
1576 begin = 0
1574 linenum = 0
1577 linenum = 0
1575 while True:
1578 while True:
1576 match = regexp.search(body, begin)
1579 match = regexp.search(body, begin)
1577 if not match:
1580 if not match:
1578 break
1581 break
1579 mstart, mend = match.span()
1582 mstart, mend = match.span()
1580 linenum += body.count('\n', begin, mstart) + 1
1583 linenum += body.count('\n', begin, mstart) + 1
1581 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1584 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1582 begin = body.find('\n', mend) + 1 or len(body)
1585 begin = body.find('\n', mend) + 1 or len(body)
1583 lend = begin - 1
1586 lend = begin - 1
1584 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1587 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1585
1588
1586 class linestate(object):
1589 class linestate(object):
1587 def __init__(self, line, linenum, colstart, colend):
1590 def __init__(self, line, linenum, colstart, colend):
1588 self.line = line
1591 self.line = line
1589 self.linenum = linenum
1592 self.linenum = linenum
1590 self.colstart = colstart
1593 self.colstart = colstart
1591 self.colend = colend
1594 self.colend = colend
1592
1595
1593 def __hash__(self):
1596 def __hash__(self):
1594 return hash((self.linenum, self.line))
1597 return hash((self.linenum, self.line))
1595
1598
1596 def __eq__(self, other):
1599 def __eq__(self, other):
1597 return self.line == other.line
1600 return self.line == other.line
1598
1601
1599 matches = {}
1602 matches = {}
1600 copies = {}
1603 copies = {}
1601 def grepbody(fn, rev, body):
1604 def grepbody(fn, rev, body):
1602 matches[rev].setdefault(fn, [])
1605 matches[rev].setdefault(fn, [])
1603 m = matches[rev][fn]
1606 m = matches[rev][fn]
1604 for lnum, cstart, cend, line in matchlines(body):
1607 for lnum, cstart, cend, line in matchlines(body):
1605 s = linestate(line, lnum, cstart, cend)
1608 s = linestate(line, lnum, cstart, cend)
1606 m.append(s)
1609 m.append(s)
1607
1610
1608 def difflinestates(a, b):
1611 def difflinestates(a, b):
1609 sm = difflib.SequenceMatcher(None, a, b)
1612 sm = difflib.SequenceMatcher(None, a, b)
1610 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1613 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1611 if tag == 'insert':
1614 if tag == 'insert':
1612 for i in xrange(blo, bhi):
1615 for i in xrange(blo, bhi):
1613 yield ('+', b[i])
1616 yield ('+', b[i])
1614 elif tag == 'delete':
1617 elif tag == 'delete':
1615 for i in xrange(alo, ahi):
1618 for i in xrange(alo, ahi):
1616 yield ('-', a[i])
1619 yield ('-', a[i])
1617 elif tag == 'replace':
1620 elif tag == 'replace':
1618 for i in xrange(alo, ahi):
1621 for i in xrange(alo, ahi):
1619 yield ('-', a[i])
1622 yield ('-', a[i])
1620 for i in xrange(blo, bhi):
1623 for i in xrange(blo, bhi):
1621 yield ('+', b[i])
1624 yield ('+', b[i])
1622
1625
1623 def display(fn, ctx, pstates, states):
1626 def display(fn, ctx, pstates, states):
1624 rev = ctx.rev()
1627 rev = ctx.rev()
1625 datefunc = ui.quiet and util.shortdate or util.datestr
1628 datefunc = ui.quiet and util.shortdate or util.datestr
1626 found = False
1629 found = False
1627 filerevmatches = {}
1630 filerevmatches = {}
1628 if opts.get('all'):
1631 if opts.get('all'):
1629 iter = difflinestates(pstates, states)
1632 iter = difflinestates(pstates, states)
1630 else:
1633 else:
1631 iter = [('', l) for l in states]
1634 iter = [('', l) for l in states]
1632 for change, l in iter:
1635 for change, l in iter:
1633 cols = [fn, str(rev)]
1636 cols = [fn, str(rev)]
1634 before, match, after = None, None, None
1637 before, match, after = None, None, None
1635 if opts.get('line_number'):
1638 if opts.get('line_number'):
1636 cols.append(str(l.linenum))
1639 cols.append(str(l.linenum))
1637 if opts.get('all'):
1640 if opts.get('all'):
1638 cols.append(change)
1641 cols.append(change)
1639 if opts.get('user'):
1642 if opts.get('user'):
1640 cols.append(ui.shortuser(ctx.user()))
1643 cols.append(ui.shortuser(ctx.user()))
1641 if opts.get('date'):
1644 if opts.get('date'):
1642 cols.append(datefunc(ctx.date()))
1645 cols.append(datefunc(ctx.date()))
1643 if opts.get('files_with_matches'):
1646 if opts.get('files_with_matches'):
1644 c = (fn, rev)
1647 c = (fn, rev)
1645 if c in filerevmatches:
1648 if c in filerevmatches:
1646 continue
1649 continue
1647 filerevmatches[c] = 1
1650 filerevmatches[c] = 1
1648 else:
1651 else:
1649 before = l.line[:l.colstart]
1652 before = l.line[:l.colstart]
1650 match = l.line[l.colstart:l.colend]
1653 match = l.line[l.colstart:l.colend]
1651 after = l.line[l.colend:]
1654 after = l.line[l.colend:]
1652 ui.write(sep.join(cols))
1655 ui.write(sep.join(cols))
1653 if before is not None:
1656 if before is not None:
1654 ui.write(sep + before)
1657 ui.write(sep + before)
1655 ui.write(match, label='grep.match')
1658 ui.write(match, label='grep.match')
1656 ui.write(after)
1659 ui.write(after)
1657 ui.write(eol)
1660 ui.write(eol)
1658 found = True
1661 found = True
1659 return found
1662 return found
1660
1663
1661 skip = {}
1664 skip = {}
1662 revfiles = {}
1665 revfiles = {}
1663 matchfn = cmdutil.match(repo, pats, opts)
1666 matchfn = cmdutil.match(repo, pats, opts)
1664 found = False
1667 found = False
1665 follow = opts.get('follow')
1668 follow = opts.get('follow')
1666
1669
1667 def prep(ctx, fns):
1670 def prep(ctx, fns):
1668 rev = ctx.rev()
1671 rev = ctx.rev()
1669 pctx = ctx.parents()[0]
1672 pctx = ctx.parents()[0]
1670 parent = pctx.rev()
1673 parent = pctx.rev()
1671 matches.setdefault(rev, {})
1674 matches.setdefault(rev, {})
1672 matches.setdefault(parent, {})
1675 matches.setdefault(parent, {})
1673 files = revfiles.setdefault(rev, [])
1676 files = revfiles.setdefault(rev, [])
1674 for fn in fns:
1677 for fn in fns:
1675 flog = getfile(fn)
1678 flog = getfile(fn)
1676 try:
1679 try:
1677 fnode = ctx.filenode(fn)
1680 fnode = ctx.filenode(fn)
1678 except error.LookupError:
1681 except error.LookupError:
1679 continue
1682 continue
1680
1683
1681 copied = flog.renamed(fnode)
1684 copied = flog.renamed(fnode)
1682 copy = follow and copied and copied[0]
1685 copy = follow and copied and copied[0]
1683 if copy:
1686 if copy:
1684 copies.setdefault(rev, {})[fn] = copy
1687 copies.setdefault(rev, {})[fn] = copy
1685 if fn in skip:
1688 if fn in skip:
1686 if copy:
1689 if copy:
1687 skip[copy] = True
1690 skip[copy] = True
1688 continue
1691 continue
1689 files.append(fn)
1692 files.append(fn)
1690
1693
1691 if fn not in matches[rev]:
1694 if fn not in matches[rev]:
1692 grepbody(fn, rev, flog.read(fnode))
1695 grepbody(fn, rev, flog.read(fnode))
1693
1696
1694 pfn = copy or fn
1697 pfn = copy or fn
1695 if pfn not in matches[parent]:
1698 if pfn not in matches[parent]:
1696 try:
1699 try:
1697 fnode = pctx.filenode(pfn)
1700 fnode = pctx.filenode(pfn)
1698 grepbody(pfn, parent, flog.read(fnode))
1701 grepbody(pfn, parent, flog.read(fnode))
1699 except error.LookupError:
1702 except error.LookupError:
1700 pass
1703 pass
1701
1704
1702 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1705 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1703 rev = ctx.rev()
1706 rev = ctx.rev()
1704 parent = ctx.parents()[0].rev()
1707 parent = ctx.parents()[0].rev()
1705 for fn in sorted(revfiles.get(rev, [])):
1708 for fn in sorted(revfiles.get(rev, [])):
1706 states = matches[rev][fn]
1709 states = matches[rev][fn]
1707 copy = copies.get(rev, {}).get(fn)
1710 copy = copies.get(rev, {}).get(fn)
1708 if fn in skip:
1711 if fn in skip:
1709 if copy:
1712 if copy:
1710 skip[copy] = True
1713 skip[copy] = True
1711 continue
1714 continue
1712 pstates = matches.get(parent, {}).get(copy or fn, [])
1715 pstates = matches.get(parent, {}).get(copy or fn, [])
1713 if pstates or states:
1716 if pstates or states:
1714 r = display(fn, ctx, pstates, states)
1717 r = display(fn, ctx, pstates, states)
1715 found = found or r
1718 found = found or r
1716 if r and not opts.get('all'):
1719 if r and not opts.get('all'):
1717 skip[fn] = True
1720 skip[fn] = True
1718 if copy:
1721 if copy:
1719 skip[copy] = True
1722 skip[copy] = True
1720 del matches[rev]
1723 del matches[rev]
1721 del revfiles[rev]
1724 del revfiles[rev]
1722
1725
1723 return not found
1726 return not found
1724
1727
1725 def heads(ui, repo, *branchrevs, **opts):
1728 def heads(ui, repo, *branchrevs, **opts):
1726 """show current repository heads or show branch heads
1729 """show current repository heads or show branch heads
1727
1730
1728 With no arguments, show all repository branch heads.
1731 With no arguments, show all repository branch heads.
1729
1732
1730 Repository "heads" are changesets with no child changesets. They are
1733 Repository "heads" are changesets with no child changesets. They are
1731 where development generally takes place and are the usual targets
1734 where development generally takes place and are the usual targets
1732 for update and merge operations. Branch heads are changesets that have
1735 for update and merge operations. Branch heads are changesets that have
1733 no child changeset on the same branch.
1736 no child changeset on the same branch.
1734
1737
1735 If one or more REVs are given, only branch heads on the branches
1738 If one or more REVs are given, only branch heads on the branches
1736 associated with the specified changesets are shown.
1739 associated with the specified changesets are shown.
1737
1740
1738 If -c/--closed is specified, also show branch heads marked closed
1741 If -c/--closed is specified, also show branch heads marked closed
1739 (see :hg:`commit --close-branch`).
1742 (see :hg:`commit --close-branch`).
1740
1743
1741 If STARTREV is specified, only those heads that are descendants of
1744 If STARTREV is specified, only those heads that are descendants of
1742 STARTREV will be displayed.
1745 STARTREV will be displayed.
1743
1746
1744 If -t/--topo is specified, named branch mechanics will be ignored and only
1747 If -t/--topo is specified, named branch mechanics will be ignored and only
1745 changesets without children will be shown.
1748 changesets without children will be shown.
1746
1749
1747 Returns 0 if matching heads are found, 1 if not.
1750 Returns 0 if matching heads are found, 1 if not.
1748 """
1751 """
1749
1752
1750 if opts.get('rev'):
1753 if opts.get('rev'):
1751 start = repo.lookup(opts['rev'])
1754 start = repo.lookup(opts['rev'])
1752 else:
1755 else:
1753 start = None
1756 start = None
1754
1757
1755 if opts.get('topo'):
1758 if opts.get('topo'):
1756 heads = [repo[h] for h in repo.heads(start)]
1759 heads = [repo[h] for h in repo.heads(start)]
1757 else:
1760 else:
1758 heads = []
1761 heads = []
1759 for b, ls in repo.branchmap().iteritems():
1762 for b, ls in repo.branchmap().iteritems():
1760 if start is None:
1763 if start is None:
1761 heads += [repo[h] for h in ls]
1764 heads += [repo[h] for h in ls]
1762 continue
1765 continue
1763 startrev = repo.changelog.rev(start)
1766 startrev = repo.changelog.rev(start)
1764 descendants = set(repo.changelog.descendants(startrev))
1767 descendants = set(repo.changelog.descendants(startrev))
1765 descendants.add(startrev)
1768 descendants.add(startrev)
1766 rev = repo.changelog.rev
1769 rev = repo.changelog.rev
1767 heads += [repo[h] for h in ls if rev(h) in descendants]
1770 heads += [repo[h] for h in ls if rev(h) in descendants]
1768
1771
1769 if branchrevs:
1772 if branchrevs:
1770 decode, encode = encoding.fromlocal, encoding.tolocal
1773 decode, encode = encoding.fromlocal, encoding.tolocal
1771 branches = set(repo[decode(br)].branch() for br in branchrevs)
1774 branches = set(repo[decode(br)].branch() for br in branchrevs)
1772 heads = [h for h in heads if h.branch() in branches]
1775 heads = [h for h in heads if h.branch() in branches]
1773
1776
1774 if not opts.get('closed'):
1777 if not opts.get('closed'):
1775 heads = [h for h in heads if not h.extra().get('close')]
1778 heads = [h for h in heads if not h.extra().get('close')]
1776
1779
1777 if opts.get('active') and branchrevs:
1780 if opts.get('active') and branchrevs:
1778 dagheads = repo.heads(start)
1781 dagheads = repo.heads(start)
1779 heads = [h for h in heads if h.node() in dagheads]
1782 heads = [h for h in heads if h.node() in dagheads]
1780
1783
1781 if branchrevs:
1784 if branchrevs:
1782 haveheads = set(h.branch() for h in heads)
1785 haveheads = set(h.branch() for h in heads)
1783 if branches - haveheads:
1786 if branches - haveheads:
1784 headless = ', '.join(encode(b) for b in branches - haveheads)
1787 headless = ', '.join(encode(b) for b in branches - haveheads)
1785 msg = _('no open branch heads found on branches %s')
1788 msg = _('no open branch heads found on branches %s')
1786 if opts.get('rev'):
1789 if opts.get('rev'):
1787 msg += _(' (started at %s)' % opts['rev'])
1790 msg += _(' (started at %s)' % opts['rev'])
1788 ui.warn((msg + '\n') % headless)
1791 ui.warn((msg + '\n') % headless)
1789
1792
1790 if not heads:
1793 if not heads:
1791 return 1
1794 return 1
1792
1795
1793 heads = sorted(heads, key=lambda x: -x.rev())
1796 heads = sorted(heads, key=lambda x: -x.rev())
1794 displayer = cmdutil.show_changeset(ui, repo, opts)
1797 displayer = cmdutil.show_changeset(ui, repo, opts)
1795 for ctx in heads:
1798 for ctx in heads:
1796 displayer.show(ctx)
1799 displayer.show(ctx)
1797 displayer.close()
1800 displayer.close()
1798
1801
1799 def help_(ui, name=None, with_version=False, unknowncmd=False):
1802 def help_(ui, name=None, with_version=False, unknowncmd=False):
1800 """show help for a given topic or a help overview
1803 """show help for a given topic or a help overview
1801
1804
1802 With no arguments, print a list of commands with short help messages.
1805 With no arguments, print a list of commands with short help messages.
1803
1806
1804 Given a topic, extension, or command name, print help for that
1807 Given a topic, extension, or command name, print help for that
1805 topic.
1808 topic.
1806
1809
1807 Returns 0 if successful.
1810 Returns 0 if successful.
1808 """
1811 """
1809 option_lists = []
1812 option_lists = []
1810 textwidth = util.termwidth() - 2
1813 textwidth = util.termwidth() - 2
1811
1814
1812 def addglobalopts(aliases):
1815 def addglobalopts(aliases):
1813 if ui.verbose:
1816 if ui.verbose:
1814 option_lists.append((_("global options:"), globalopts))
1817 option_lists.append((_("global options:"), globalopts))
1815 if name == 'shortlist':
1818 if name == 'shortlist':
1816 option_lists.append((_('use "hg help" for the full list '
1819 option_lists.append((_('use "hg help" for the full list '
1817 'of commands'), ()))
1820 'of commands'), ()))
1818 else:
1821 else:
1819 if name == 'shortlist':
1822 if name == 'shortlist':
1820 msg = _('use "hg help" for the full list of commands '
1823 msg = _('use "hg help" for the full list of commands '
1821 'or "hg -v" for details')
1824 'or "hg -v" for details')
1822 elif aliases:
1825 elif aliases:
1823 msg = _('use "hg -v help%s" to show aliases and '
1826 msg = _('use "hg -v help%s" to show aliases and '
1824 'global options') % (name and " " + name or "")
1827 'global options') % (name and " " + name or "")
1825 else:
1828 else:
1826 msg = _('use "hg -v help %s" to show global options') % name
1829 msg = _('use "hg -v help %s" to show global options') % name
1827 option_lists.append((msg, ()))
1830 option_lists.append((msg, ()))
1828
1831
1829 def helpcmd(name):
1832 def helpcmd(name):
1830 if with_version:
1833 if with_version:
1831 version_(ui)
1834 version_(ui)
1832 ui.write('\n')
1835 ui.write('\n')
1833
1836
1834 try:
1837 try:
1835 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1838 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1836 except error.AmbiguousCommand, inst:
1839 except error.AmbiguousCommand, inst:
1837 # py3k fix: except vars can't be used outside the scope of the
1840 # py3k fix: except vars can't be used outside the scope of the
1838 # except block, nor can be used inside a lambda. python issue4617
1841 # except block, nor can be used inside a lambda. python issue4617
1839 prefix = inst.args[0]
1842 prefix = inst.args[0]
1840 select = lambda c: c.lstrip('^').startswith(prefix)
1843 select = lambda c: c.lstrip('^').startswith(prefix)
1841 helplist(_('list of commands:\n\n'), select)
1844 helplist(_('list of commands:\n\n'), select)
1842 return
1845 return
1843
1846
1844 # check if it's an invalid alias and display its error if it is
1847 # check if it's an invalid alias and display its error if it is
1845 if getattr(entry[0], 'badalias', False):
1848 if getattr(entry[0], 'badalias', False):
1846 if not unknowncmd:
1849 if not unknowncmd:
1847 entry[0](ui)
1850 entry[0](ui)
1848 return
1851 return
1849
1852
1850 # synopsis
1853 # synopsis
1851 if len(entry) > 2:
1854 if len(entry) > 2:
1852 if entry[2].startswith('hg'):
1855 if entry[2].startswith('hg'):
1853 ui.write("%s\n" % entry[2])
1856 ui.write("%s\n" % entry[2])
1854 else:
1857 else:
1855 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1858 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1856 else:
1859 else:
1857 ui.write('hg %s\n' % aliases[0])
1860 ui.write('hg %s\n' % aliases[0])
1858
1861
1859 # aliases
1862 # aliases
1860 if not ui.quiet and len(aliases) > 1:
1863 if not ui.quiet and len(aliases) > 1:
1861 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1864 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1862
1865
1863 # description
1866 # description
1864 doc = gettext(entry[0].__doc__)
1867 doc = gettext(entry[0].__doc__)
1865 if not doc:
1868 if not doc:
1866 doc = _("(no help text available)")
1869 doc = _("(no help text available)")
1867 if hasattr(entry[0], 'definition'): # aliased command
1870 if hasattr(entry[0], 'definition'): # aliased command
1868 if entry[0].definition.startswith('!'): # shell alias
1871 if entry[0].definition.startswith('!'): # shell alias
1869 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1872 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1870 else:
1873 else:
1871 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1874 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1872 if ui.quiet:
1875 if ui.quiet:
1873 doc = doc.splitlines()[0]
1876 doc = doc.splitlines()[0]
1874 keep = ui.verbose and ['verbose'] or []
1877 keep = ui.verbose and ['verbose'] or []
1875 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1878 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1876 ui.write("\n%s\n" % formatted)
1879 ui.write("\n%s\n" % formatted)
1877 if pruned:
1880 if pruned:
1878 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1881 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1879
1882
1880 if not ui.quiet:
1883 if not ui.quiet:
1881 # options
1884 # options
1882 if entry[1]:
1885 if entry[1]:
1883 option_lists.append((_("options:\n"), entry[1]))
1886 option_lists.append((_("options:\n"), entry[1]))
1884
1887
1885 addglobalopts(False)
1888 addglobalopts(False)
1886
1889
1887 def helplist(header, select=None):
1890 def helplist(header, select=None):
1888 h = {}
1891 h = {}
1889 cmds = {}
1892 cmds = {}
1890 for c, e in table.iteritems():
1893 for c, e in table.iteritems():
1891 f = c.split("|", 1)[0]
1894 f = c.split("|", 1)[0]
1892 if select and not select(f):
1895 if select and not select(f):
1893 continue
1896 continue
1894 if (not select and name != 'shortlist' and
1897 if (not select and name != 'shortlist' and
1895 e[0].__module__ != __name__):
1898 e[0].__module__ != __name__):
1896 continue
1899 continue
1897 if name == "shortlist" and not f.startswith("^"):
1900 if name == "shortlist" and not f.startswith("^"):
1898 continue
1901 continue
1899 f = f.lstrip("^")
1902 f = f.lstrip("^")
1900 if not ui.debugflag and f.startswith("debug"):
1903 if not ui.debugflag and f.startswith("debug"):
1901 continue
1904 continue
1902 doc = e[0].__doc__
1905 doc = e[0].__doc__
1903 if doc and 'DEPRECATED' in doc and not ui.verbose:
1906 if doc and 'DEPRECATED' in doc and not ui.verbose:
1904 continue
1907 continue
1905 doc = gettext(doc)
1908 doc = gettext(doc)
1906 if not doc:
1909 if not doc:
1907 doc = _("(no help text available)")
1910 doc = _("(no help text available)")
1908 h[f] = doc.splitlines()[0].rstrip()
1911 h[f] = doc.splitlines()[0].rstrip()
1909 cmds[f] = c.lstrip("^")
1912 cmds[f] = c.lstrip("^")
1910
1913
1911 if not h:
1914 if not h:
1912 ui.status(_('no commands defined\n'))
1915 ui.status(_('no commands defined\n'))
1913 return
1916 return
1914
1917
1915 ui.status(header)
1918 ui.status(header)
1916 fns = sorted(h)
1919 fns = sorted(h)
1917 m = max(map(len, fns))
1920 m = max(map(len, fns))
1918 for f in fns:
1921 for f in fns:
1919 if ui.verbose:
1922 if ui.verbose:
1920 commands = cmds[f].replace("|",", ")
1923 commands = cmds[f].replace("|",", ")
1921 ui.write(" %s:\n %s\n"%(commands, h[f]))
1924 ui.write(" %s:\n %s\n"%(commands, h[f]))
1922 else:
1925 else:
1923 ui.write('%s\n' % (util.wrap(h[f],
1926 ui.write('%s\n' % (util.wrap(h[f],
1924 initindent=' %-*s ' % (m, f),
1927 initindent=' %-*s ' % (m, f),
1925 hangindent=' ' * (m + 4))))
1928 hangindent=' ' * (m + 4))))
1926
1929
1927 if not ui.quiet:
1930 if not ui.quiet:
1928 addglobalopts(True)
1931 addglobalopts(True)
1929
1932
1930 def helptopic(name):
1933 def helptopic(name):
1931 for names, header, doc in help.helptable:
1934 for names, header, doc in help.helptable:
1932 if name in names:
1935 if name in names:
1933 break
1936 break
1934 else:
1937 else:
1935 raise error.UnknownCommand(name)
1938 raise error.UnknownCommand(name)
1936
1939
1937 # description
1940 # description
1938 if not doc:
1941 if not doc:
1939 doc = _("(no help text available)")
1942 doc = _("(no help text available)")
1940 if hasattr(doc, '__call__'):
1943 if hasattr(doc, '__call__'):
1941 doc = doc()
1944 doc = doc()
1942
1945
1943 ui.write("%s\n\n" % header)
1946 ui.write("%s\n\n" % header)
1944 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1947 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1945
1948
1946 def helpext(name):
1949 def helpext(name):
1947 try:
1950 try:
1948 mod = extensions.find(name)
1951 mod = extensions.find(name)
1949 doc = gettext(mod.__doc__) or _('no help text available')
1952 doc = gettext(mod.__doc__) or _('no help text available')
1950 except KeyError:
1953 except KeyError:
1951 mod = None
1954 mod = None
1952 doc = extensions.disabledext(name)
1955 doc = extensions.disabledext(name)
1953 if not doc:
1956 if not doc:
1954 raise error.UnknownCommand(name)
1957 raise error.UnknownCommand(name)
1955
1958
1956 if '\n' not in doc:
1959 if '\n' not in doc:
1957 head, tail = doc, ""
1960 head, tail = doc, ""
1958 else:
1961 else:
1959 head, tail = doc.split('\n', 1)
1962 head, tail = doc.split('\n', 1)
1960 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1963 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1961 if tail:
1964 if tail:
1962 ui.write(minirst.format(tail, textwidth))
1965 ui.write(minirst.format(tail, textwidth))
1963 ui.status('\n\n')
1966 ui.status('\n\n')
1964
1967
1965 if mod:
1968 if mod:
1966 try:
1969 try:
1967 ct = mod.cmdtable
1970 ct = mod.cmdtable
1968 except AttributeError:
1971 except AttributeError:
1969 ct = {}
1972 ct = {}
1970 modcmds = set([c.split('|', 1)[0] for c in ct])
1973 modcmds = set([c.split('|', 1)[0] for c in ct])
1971 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1974 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1972 else:
1975 else:
1973 ui.write(_('use "hg help extensions" for information on enabling '
1976 ui.write(_('use "hg help extensions" for information on enabling '
1974 'extensions\n'))
1977 'extensions\n'))
1975
1978
1976 def helpextcmd(name):
1979 def helpextcmd(name):
1977 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
1980 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
1978 doc = gettext(mod.__doc__).splitlines()[0]
1981 doc = gettext(mod.__doc__).splitlines()[0]
1979
1982
1980 msg = help.listexts(_("'%s' is provided by the following "
1983 msg = help.listexts(_("'%s' is provided by the following "
1981 "extension:") % cmd, {ext: doc}, len(ext),
1984 "extension:") % cmd, {ext: doc}, len(ext),
1982 indent=4)
1985 indent=4)
1983 ui.write(minirst.format(msg, textwidth))
1986 ui.write(minirst.format(msg, textwidth))
1984 ui.write('\n\n')
1987 ui.write('\n\n')
1985 ui.write(_('use "hg help extensions" for information on enabling '
1988 ui.write(_('use "hg help extensions" for information on enabling '
1986 'extensions\n'))
1989 'extensions\n'))
1987
1990
1988 if name and name != 'shortlist':
1991 if name and name != 'shortlist':
1989 i = None
1992 i = None
1990 if unknowncmd:
1993 if unknowncmd:
1991 queries = (helpextcmd,)
1994 queries = (helpextcmd,)
1992 else:
1995 else:
1993 queries = (helptopic, helpcmd, helpext, helpextcmd)
1996 queries = (helptopic, helpcmd, helpext, helpextcmd)
1994 for f in queries:
1997 for f in queries:
1995 try:
1998 try:
1996 f(name)
1999 f(name)
1997 i = None
2000 i = None
1998 break
2001 break
1999 except error.UnknownCommand, inst:
2002 except error.UnknownCommand, inst:
2000 i = inst
2003 i = inst
2001 if i:
2004 if i:
2002 raise i
2005 raise i
2003
2006
2004 else:
2007 else:
2005 # program name
2008 # program name
2006 if ui.verbose or with_version:
2009 if ui.verbose or with_version:
2007 version_(ui)
2010 version_(ui)
2008 else:
2011 else:
2009 ui.status(_("Mercurial Distributed SCM\n"))
2012 ui.status(_("Mercurial Distributed SCM\n"))
2010 ui.status('\n')
2013 ui.status('\n')
2011
2014
2012 # list of commands
2015 # list of commands
2013 if name == "shortlist":
2016 if name == "shortlist":
2014 header = _('basic commands:\n\n')
2017 header = _('basic commands:\n\n')
2015 else:
2018 else:
2016 header = _('list of commands:\n\n')
2019 header = _('list of commands:\n\n')
2017
2020
2018 helplist(header)
2021 helplist(header)
2019 if name != 'shortlist':
2022 if name != 'shortlist':
2020 exts, maxlength = extensions.enabled()
2023 exts, maxlength = extensions.enabled()
2021 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2024 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2022 if text:
2025 if text:
2023 ui.write("\n%s\n" % minirst.format(text, textwidth))
2026 ui.write("\n%s\n" % minirst.format(text, textwidth))
2024
2027
2025 # list all option lists
2028 # list all option lists
2026 opt_output = []
2029 opt_output = []
2027 multioccur = False
2030 multioccur = False
2028 for title, options in option_lists:
2031 for title, options in option_lists:
2029 opt_output.append(("\n%s" % title, None))
2032 opt_output.append(("\n%s" % title, None))
2030 for option in options:
2033 for option in options:
2031 if len(option) == 5:
2034 if len(option) == 5:
2032 shortopt, longopt, default, desc, optlabel = option
2035 shortopt, longopt, default, desc, optlabel = option
2033 else:
2036 else:
2034 shortopt, longopt, default, desc = option
2037 shortopt, longopt, default, desc = option
2035 optlabel = _("VALUE") # default label
2038 optlabel = _("VALUE") # default label
2036
2039
2037 if _("DEPRECATED") in desc and not ui.verbose:
2040 if _("DEPRECATED") in desc and not ui.verbose:
2038 continue
2041 continue
2039 if isinstance(default, list):
2042 if isinstance(default, list):
2040 numqualifier = " %s [+]" % optlabel
2043 numqualifier = " %s [+]" % optlabel
2041 multioccur = True
2044 multioccur = True
2042 elif (default is not None) and not isinstance(default, bool):
2045 elif (default is not None) and not isinstance(default, bool):
2043 numqualifier = " %s" % optlabel
2046 numqualifier = " %s" % optlabel
2044 else:
2047 else:
2045 numqualifier = ""
2048 numqualifier = ""
2046 opt_output.append(("%2s%s" %
2049 opt_output.append(("%2s%s" %
2047 (shortopt and "-%s" % shortopt,
2050 (shortopt and "-%s" % shortopt,
2048 longopt and " --%s%s" %
2051 longopt and " --%s%s" %
2049 (longopt, numqualifier)),
2052 (longopt, numqualifier)),
2050 "%s%s" % (desc,
2053 "%s%s" % (desc,
2051 default
2054 default
2052 and _(" (default: %s)") % default
2055 and _(" (default: %s)") % default
2053 or "")))
2056 or "")))
2054 if multioccur:
2057 if multioccur:
2055 msg = _("\n[+] marked option can be specified multiple times")
2058 msg = _("\n[+] marked option can be specified multiple times")
2056 if ui.verbose and name != 'shortlist':
2059 if ui.verbose and name != 'shortlist':
2057 opt_output.append((msg, None))
2060 opt_output.append((msg, None))
2058 else:
2061 else:
2059 opt_output.insert(-1, (msg, None))
2062 opt_output.insert(-1, (msg, None))
2060
2063
2061 if not name:
2064 if not name:
2062 ui.write(_("\nadditional help topics:\n\n"))
2065 ui.write(_("\nadditional help topics:\n\n"))
2063 topics = []
2066 topics = []
2064 for names, header, doc in help.helptable:
2067 for names, header, doc in help.helptable:
2065 topics.append((sorted(names, key=len, reverse=True)[0], header))
2068 topics.append((sorted(names, key=len, reverse=True)[0], header))
2066 topics_len = max([len(s[0]) for s in topics])
2069 topics_len = max([len(s[0]) for s in topics])
2067 for t, desc in topics:
2070 for t, desc in topics:
2068 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2071 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2069
2072
2070 if opt_output:
2073 if opt_output:
2071 colwidth = encoding.colwidth
2074 colwidth = encoding.colwidth
2072 # normalize: (opt or message, desc or None, width of opt)
2075 # normalize: (opt or message, desc or None, width of opt)
2073 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2076 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2074 for opt, desc in opt_output]
2077 for opt, desc in opt_output]
2075 hanging = max([e[2] for e in entries])
2078 hanging = max([e[2] for e in entries])
2076 for opt, desc, width in entries:
2079 for opt, desc, width in entries:
2077 if desc:
2080 if desc:
2078 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2081 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2079 hangindent = ' ' * (hanging + 3)
2082 hangindent = ' ' * (hanging + 3)
2080 ui.write('%s\n' % (util.wrap(desc,
2083 ui.write('%s\n' % (util.wrap(desc,
2081 initindent=initindent,
2084 initindent=initindent,
2082 hangindent=hangindent)))
2085 hangindent=hangindent)))
2083 else:
2086 else:
2084 ui.write("%s\n" % opt)
2087 ui.write("%s\n" % opt)
2085
2088
2086 def identify(ui, repo, source=None,
2089 def identify(ui, repo, source=None,
2087 rev=None, num=None, id=None, branch=None, tags=None):
2090 rev=None, num=None, id=None, branch=None, tags=None):
2088 """identify the working copy or specified revision
2091 """identify the working copy or specified revision
2089
2092
2090 With no revision, print a summary of the current state of the
2093 With no revision, print a summary of the current state of the
2091 repository.
2094 repository.
2092
2095
2093 Specifying a path to a repository root or Mercurial bundle will
2096 Specifying a path to a repository root or Mercurial bundle will
2094 cause lookup to operate on that repository/bundle.
2097 cause lookup to operate on that repository/bundle.
2095
2098
2096 This summary identifies the repository state using one or two
2099 This summary identifies the repository state using one or two
2097 parent hash identifiers, followed by a "+" if there are
2100 parent hash identifiers, followed by a "+" if there are
2098 uncommitted changes in the working directory, a list of tags for
2101 uncommitted changes in the working directory, a list of tags for
2099 this revision and a branch name for non-default branches.
2102 this revision and a branch name for non-default branches.
2100
2103
2101 Returns 0 if successful.
2104 Returns 0 if successful.
2102 """
2105 """
2103
2106
2104 if not repo and not source:
2107 if not repo and not source:
2105 raise util.Abort(_("there is no Mercurial repository here "
2108 raise util.Abort(_("there is no Mercurial repository here "
2106 "(.hg not found)"))
2109 "(.hg not found)"))
2107
2110
2108 hexfunc = ui.debugflag and hex or short
2111 hexfunc = ui.debugflag and hex or short
2109 default = not (num or id or branch or tags)
2112 default = not (num or id or branch or tags)
2110 output = []
2113 output = []
2111
2114
2112 revs = []
2115 revs = []
2113 if source:
2116 if source:
2114 source, branches = hg.parseurl(ui.expandpath(source))
2117 source, branches = hg.parseurl(ui.expandpath(source))
2115 repo = hg.repository(ui, source)
2118 repo = hg.repository(ui, source)
2116 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2119 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2117
2120
2118 if not repo.local():
2121 if not repo.local():
2119 if not rev and revs:
2122 if not rev and revs:
2120 rev = revs[0]
2123 rev = revs[0]
2121 if not rev:
2124 if not rev:
2122 rev = "tip"
2125 rev = "tip"
2123 if num or branch or tags:
2126 if num or branch or tags:
2124 raise util.Abort(
2127 raise util.Abort(
2125 "can't query remote revision number, branch, or tags")
2128 "can't query remote revision number, branch, or tags")
2126 output = [hexfunc(repo.lookup(rev))]
2129 output = [hexfunc(repo.lookup(rev))]
2127 elif not rev:
2130 elif not rev:
2128 ctx = repo[None]
2131 ctx = repo[None]
2129 parents = ctx.parents()
2132 parents = ctx.parents()
2130 changed = False
2133 changed = False
2131 if default or id or num:
2134 if default or id or num:
2132 changed = util.any(repo.status())
2135 changed = util.any(repo.status())
2133 if default or id:
2136 if default or id:
2134 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2137 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2135 (changed) and "+" or "")]
2138 (changed) and "+" or "")]
2136 if num:
2139 if num:
2137 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2140 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2138 (changed) and "+" or ""))
2141 (changed) and "+" or ""))
2139 else:
2142 else:
2140 ctx = repo[rev]
2143 ctx = repo[rev]
2141 if default or id:
2144 if default or id:
2142 output = [hexfunc(ctx.node())]
2145 output = [hexfunc(ctx.node())]
2143 if num:
2146 if num:
2144 output.append(str(ctx.rev()))
2147 output.append(str(ctx.rev()))
2145
2148
2146 if repo.local() and default and not ui.quiet:
2149 if repo.local() and default and not ui.quiet:
2147 b = encoding.tolocal(ctx.branch())
2150 b = encoding.tolocal(ctx.branch())
2148 if b != 'default':
2151 if b != 'default':
2149 output.append("(%s)" % b)
2152 output.append("(%s)" % b)
2150
2153
2151 # multiple tags for a single parent separated by '/'
2154 # multiple tags for a single parent separated by '/'
2152 t = "/".join(ctx.tags())
2155 t = "/".join(ctx.tags())
2153 if t:
2156 if t:
2154 output.append(t)
2157 output.append(t)
2155
2158
2156 if branch:
2159 if branch:
2157 output.append(encoding.tolocal(ctx.branch()))
2160 output.append(encoding.tolocal(ctx.branch()))
2158
2161
2159 if tags:
2162 if tags:
2160 output.extend(ctx.tags())
2163 output.extend(ctx.tags())
2161
2164
2162 ui.write("%s\n" % ' '.join(output))
2165 ui.write("%s\n" % ' '.join(output))
2163
2166
2164 def import_(ui, repo, patch1, *patches, **opts):
2167 def import_(ui, repo, patch1, *patches, **opts):
2165 """import an ordered set of patches
2168 """import an ordered set of patches
2166
2169
2167 Import a list of patches and commit them individually (unless
2170 Import a list of patches and commit them individually (unless
2168 --no-commit is specified).
2171 --no-commit is specified).
2169
2172
2170 If there are outstanding changes in the working directory, import
2173 If there are outstanding changes in the working directory, import
2171 will abort unless given the -f/--force flag.
2174 will abort unless given the -f/--force flag.
2172
2175
2173 You can import a patch straight from a mail message. Even patches
2176 You can import a patch straight from a mail message. Even patches
2174 as attachments work (to use the body part, it must have type
2177 as attachments work (to use the body part, it must have type
2175 text/plain or text/x-patch). From and Subject headers of email
2178 text/plain or text/x-patch). From and Subject headers of email
2176 message are used as default committer and commit message. All
2179 message are used as default committer and commit message. All
2177 text/plain body parts before first diff are added to commit
2180 text/plain body parts before first diff are added to commit
2178 message.
2181 message.
2179
2182
2180 If the imported patch was generated by :hg:`export`, user and
2183 If the imported patch was generated by :hg:`export`, user and
2181 description from patch override values from message headers and
2184 description from patch override values from message headers and
2182 body. Values given on command line with -m/--message and -u/--user
2185 body. Values given on command line with -m/--message and -u/--user
2183 override these.
2186 override these.
2184
2187
2185 If --exact is specified, import will set the working directory to
2188 If --exact is specified, import will set the working directory to
2186 the parent of each patch before applying it, and will abort if the
2189 the parent of each patch before applying it, and will abort if the
2187 resulting changeset has a different ID than the one recorded in
2190 resulting changeset has a different ID than the one recorded in
2188 the patch. This may happen due to character set problems or other
2191 the patch. This may happen due to character set problems or other
2189 deficiencies in the text patch format.
2192 deficiencies in the text patch format.
2190
2193
2191 With -s/--similarity, hg will attempt to discover renames and
2194 With -s/--similarity, hg will attempt to discover renames and
2192 copies in the patch in the same way as 'addremove'.
2195 copies in the patch in the same way as 'addremove'.
2193
2196
2194 To read a patch from standard input, use "-" as the patch name. If
2197 To read a patch from standard input, use "-" as the patch name. If
2195 a URL is specified, the patch will be downloaded from it.
2198 a URL is specified, the patch will be downloaded from it.
2196 See :hg:`help dates` for a list of formats valid for -d/--date.
2199 See :hg:`help dates` for a list of formats valid for -d/--date.
2197
2200
2198 Returns 0 on success.
2201 Returns 0 on success.
2199 """
2202 """
2200 patches = (patch1,) + patches
2203 patches = (patch1,) + patches
2201
2204
2202 date = opts.get('date')
2205 date = opts.get('date')
2203 if date:
2206 if date:
2204 opts['date'] = util.parsedate(date)
2207 opts['date'] = util.parsedate(date)
2205
2208
2206 try:
2209 try:
2207 sim = float(opts.get('similarity') or 0)
2210 sim = float(opts.get('similarity') or 0)
2208 except ValueError:
2211 except ValueError:
2209 raise util.Abort(_('similarity must be a number'))
2212 raise util.Abort(_('similarity must be a number'))
2210 if sim < 0 or sim > 100:
2213 if sim < 0 or sim > 100:
2211 raise util.Abort(_('similarity must be between 0 and 100'))
2214 raise util.Abort(_('similarity must be between 0 and 100'))
2212
2215
2213 if opts.get('exact') or not opts.get('force'):
2216 if opts.get('exact') or not opts.get('force'):
2214 cmdutil.bail_if_changed(repo)
2217 cmdutil.bail_if_changed(repo)
2215
2218
2216 d = opts["base"]
2219 d = opts["base"]
2217 strip = opts["strip"]
2220 strip = opts["strip"]
2218 wlock = lock = None
2221 wlock = lock = None
2219
2222
2220 def tryone(ui, hunk):
2223 def tryone(ui, hunk):
2221 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2224 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2222 patch.extract(ui, hunk)
2225 patch.extract(ui, hunk)
2223
2226
2224 if not tmpname:
2227 if not tmpname:
2225 return None
2228 return None
2226 commitid = _('to working directory')
2229 commitid = _('to working directory')
2227
2230
2228 try:
2231 try:
2229 cmdline_message = cmdutil.logmessage(opts)
2232 cmdline_message = cmdutil.logmessage(opts)
2230 if cmdline_message:
2233 if cmdline_message:
2231 # pickup the cmdline msg
2234 # pickup the cmdline msg
2232 message = cmdline_message
2235 message = cmdline_message
2233 elif message:
2236 elif message:
2234 # pickup the patch msg
2237 # pickup the patch msg
2235 message = message.strip()
2238 message = message.strip()
2236 else:
2239 else:
2237 # launch the editor
2240 # launch the editor
2238 message = None
2241 message = None
2239 ui.debug('message:\n%s\n' % message)
2242 ui.debug('message:\n%s\n' % message)
2240
2243
2241 wp = repo.parents()
2244 wp = repo.parents()
2242 if opts.get('exact'):
2245 if opts.get('exact'):
2243 if not nodeid or not p1:
2246 if not nodeid or not p1:
2244 raise util.Abort(_('not a Mercurial patch'))
2247 raise util.Abort(_('not a Mercurial patch'))
2245 p1 = repo.lookup(p1)
2248 p1 = repo.lookup(p1)
2246 p2 = repo.lookup(p2 or hex(nullid))
2249 p2 = repo.lookup(p2 or hex(nullid))
2247
2250
2248 if p1 != wp[0].node():
2251 if p1 != wp[0].node():
2249 hg.clean(repo, p1)
2252 hg.clean(repo, p1)
2250 repo.dirstate.setparents(p1, p2)
2253 repo.dirstate.setparents(p1, p2)
2251 elif p2:
2254 elif p2:
2252 try:
2255 try:
2253 p1 = repo.lookup(p1)
2256 p1 = repo.lookup(p1)
2254 p2 = repo.lookup(p2)
2257 p2 = repo.lookup(p2)
2255 if p1 == wp[0].node():
2258 if p1 == wp[0].node():
2256 repo.dirstate.setparents(p1, p2)
2259 repo.dirstate.setparents(p1, p2)
2257 except error.RepoError:
2260 except error.RepoError:
2258 pass
2261 pass
2259 if opts.get('exact') or opts.get('import_branch'):
2262 if opts.get('exact') or opts.get('import_branch'):
2260 repo.dirstate.setbranch(branch or 'default')
2263 repo.dirstate.setbranch(branch or 'default')
2261
2264
2262 files = {}
2265 files = {}
2263 try:
2266 try:
2264 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2267 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2265 files=files, eolmode=None)
2268 files=files, eolmode=None)
2266 finally:
2269 finally:
2267 files = patch.updatedir(ui, repo, files,
2270 files = patch.updatedir(ui, repo, files,
2268 similarity=sim / 100.0)
2271 similarity=sim / 100.0)
2269 if not opts.get('no_commit'):
2272 if not opts.get('no_commit'):
2270 if opts.get('exact'):
2273 if opts.get('exact'):
2271 m = None
2274 m = None
2272 else:
2275 else:
2273 m = cmdutil.matchfiles(repo, files or [])
2276 m = cmdutil.matchfiles(repo, files or [])
2274 n = repo.commit(message, opts.get('user') or user,
2277 n = repo.commit(message, opts.get('user') or user,
2275 opts.get('date') or date, match=m,
2278 opts.get('date') or date, match=m,
2276 editor=cmdutil.commiteditor)
2279 editor=cmdutil.commiteditor)
2277 if opts.get('exact'):
2280 if opts.get('exact'):
2278 if hex(n) != nodeid:
2281 if hex(n) != nodeid:
2279 repo.rollback()
2282 repo.rollback()
2280 raise util.Abort(_('patch is damaged'
2283 raise util.Abort(_('patch is damaged'
2281 ' or loses information'))
2284 ' or loses information'))
2282 # Force a dirstate write so that the next transaction
2285 # Force a dirstate write so that the next transaction
2283 # backups an up-do-date file.
2286 # backups an up-do-date file.
2284 repo.dirstate.write()
2287 repo.dirstate.write()
2285 if n:
2288 if n:
2286 commitid = short(n)
2289 commitid = short(n)
2287
2290
2288 return commitid
2291 return commitid
2289 finally:
2292 finally:
2290 os.unlink(tmpname)
2293 os.unlink(tmpname)
2291
2294
2292 try:
2295 try:
2293 wlock = repo.wlock()
2296 wlock = repo.wlock()
2294 lock = repo.lock()
2297 lock = repo.lock()
2295 lastcommit = None
2298 lastcommit = None
2296 for p in patches:
2299 for p in patches:
2297 pf = os.path.join(d, p)
2300 pf = os.path.join(d, p)
2298
2301
2299 if pf == '-':
2302 if pf == '-':
2300 ui.status(_("applying patch from stdin\n"))
2303 ui.status(_("applying patch from stdin\n"))
2301 pf = sys.stdin
2304 pf = sys.stdin
2302 else:
2305 else:
2303 ui.status(_("applying %s\n") % p)
2306 ui.status(_("applying %s\n") % p)
2304 pf = url.open(ui, pf)
2307 pf = url.open(ui, pf)
2305
2308
2306 haspatch = False
2309 haspatch = False
2307 for hunk in patch.split(pf):
2310 for hunk in patch.split(pf):
2308 commitid = tryone(ui, hunk)
2311 commitid = tryone(ui, hunk)
2309 if commitid:
2312 if commitid:
2310 haspatch = True
2313 haspatch = True
2311 if lastcommit:
2314 if lastcommit:
2312 ui.status(_('applied %s\n') % lastcommit)
2315 ui.status(_('applied %s\n') % lastcommit)
2313 lastcommit = commitid
2316 lastcommit = commitid
2314
2317
2315 if not haspatch:
2318 if not haspatch:
2316 raise util.Abort(_('no diffs found'))
2319 raise util.Abort(_('no diffs found'))
2317
2320
2318 finally:
2321 finally:
2319 release(lock, wlock)
2322 release(lock, wlock)
2320
2323
2321 def incoming(ui, repo, source="default", **opts):
2324 def incoming(ui, repo, source="default", **opts):
2322 """show new changesets found in source
2325 """show new changesets found in source
2323
2326
2324 Show new changesets found in the specified path/URL or the default
2327 Show new changesets found in the specified path/URL or the default
2325 pull location. These are the changesets that would have been pulled
2328 pull location. These are the changesets that would have been pulled
2326 if a pull at the time you issued this command.
2329 if a pull at the time you issued this command.
2327
2330
2328 For remote repository, using --bundle avoids downloading the
2331 For remote repository, using --bundle avoids downloading the
2329 changesets twice if the incoming is followed by a pull.
2332 changesets twice if the incoming is followed by a pull.
2330
2333
2331 See pull for valid source format details.
2334 See pull for valid source format details.
2332
2335
2333 Returns 0 if there are incoming changes, 1 otherwise.
2336 Returns 0 if there are incoming changes, 1 otherwise.
2334 """
2337 """
2335 limit = cmdutil.loglimit(opts)
2338 limit = cmdutil.loglimit(opts)
2336 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2339 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2337 other = hg.repository(hg.remoteui(repo, opts), source)
2340 other = hg.repository(hg.remoteui(repo, opts), source)
2338 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2341 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2339 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2342 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2340 if revs:
2343 if revs:
2341 revs = [other.lookup(rev) for rev in revs]
2344 revs = [other.lookup(rev) for rev in revs]
2342
2345
2343 tmp = discovery.findcommonincoming(repo, other, heads=revs,
2346 tmp = discovery.findcommonincoming(repo, other, heads=revs,
2344 force=opts.get('force'))
2347 force=opts.get('force'))
2345 common, incoming, rheads = tmp
2348 common, incoming, rheads = tmp
2346 if not incoming:
2349 if not incoming:
2347 try:
2350 try:
2348 os.unlink(opts["bundle"])
2351 os.unlink(opts["bundle"])
2349 except:
2352 except:
2350 pass
2353 pass
2351 ui.status(_("no changes found\n"))
2354 ui.status(_("no changes found\n"))
2352 return 1
2355 return 1
2353
2356
2354 cleanup = None
2357 cleanup = None
2355 try:
2358 try:
2356 fname = opts["bundle"]
2359 fname = opts["bundle"]
2357 if fname or not other.local():
2360 if fname or not other.local():
2358 # create a bundle (uncompressed if other repo is not local)
2361 # create a bundle (uncompressed if other repo is not local)
2359
2362
2360 if revs is None and other.capable('changegroupsubset'):
2363 if revs is None and other.capable('changegroupsubset'):
2361 revs = rheads
2364 revs = rheads
2362
2365
2363 if revs is None:
2366 if revs is None:
2364 cg = other.changegroup(incoming, "incoming")
2367 cg = other.changegroup(incoming, "incoming")
2365 else:
2368 else:
2366 cg = other.changegroupsubset(incoming, revs, 'incoming')
2369 cg = other.changegroupsubset(incoming, revs, 'incoming')
2367 bundletype = other.local() and "HG10BZ" or "HG10UN"
2370 bundletype = other.local() and "HG10BZ" or "HG10UN"
2368 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
2371 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
2369 # keep written bundle?
2372 # keep written bundle?
2370 if opts["bundle"]:
2373 if opts["bundle"]:
2371 cleanup = None
2374 cleanup = None
2372 if not other.local():
2375 if not other.local():
2373 # use the created uncompressed bundlerepo
2376 # use the created uncompressed bundlerepo
2374 other = bundlerepo.bundlerepository(ui, repo.root, fname)
2377 other = bundlerepo.bundlerepository(ui, repo.root, fname)
2375
2378
2376 o = other.changelog.nodesbetween(incoming, revs)[0]
2379 o = other.changelog.nodesbetween(incoming, revs)[0]
2377 if opts.get('newest_first'):
2380 if opts.get('newest_first'):
2378 o.reverse()
2381 o.reverse()
2379 displayer = cmdutil.show_changeset(ui, other, opts)
2382 displayer = cmdutil.show_changeset(ui, other, opts)
2380 count = 0
2383 count = 0
2381 for n in o:
2384 for n in o:
2382 if limit is not None and count >= limit:
2385 if limit is not None and count >= limit:
2383 break
2386 break
2384 parents = [p for p in other.changelog.parents(n) if p != nullid]
2387 parents = [p for p in other.changelog.parents(n) if p != nullid]
2385 if opts.get('no_merges') and len(parents) == 2:
2388 if opts.get('no_merges') and len(parents) == 2:
2386 continue
2389 continue
2387 count += 1
2390 count += 1
2388 displayer.show(other[n])
2391 displayer.show(other[n])
2389 displayer.close()
2392 displayer.close()
2390 finally:
2393 finally:
2391 if hasattr(other, 'close'):
2394 if hasattr(other, 'close'):
2392 other.close()
2395 other.close()
2393 if cleanup:
2396 if cleanup:
2394 os.unlink(cleanup)
2397 os.unlink(cleanup)
2395
2398
2396 def init(ui, dest=".", **opts):
2399 def init(ui, dest=".", **opts):
2397 """create a new repository in the given directory
2400 """create a new repository in the given directory
2398
2401
2399 Initialize a new repository in the given directory. If the given
2402 Initialize a new repository in the given directory. If the given
2400 directory does not exist, it will be created.
2403 directory does not exist, it will be created.
2401
2404
2402 If no directory is given, the current directory is used.
2405 If no directory is given, the current directory is used.
2403
2406
2404 It is possible to specify an ``ssh://`` URL as the destination.
2407 It is possible to specify an ``ssh://`` URL as the destination.
2405 See :hg:`help urls` for more information.
2408 See :hg:`help urls` for more information.
2406
2409
2407 Returns 0 on success.
2410 Returns 0 on success.
2408 """
2411 """
2409 hg.repository(hg.remoteui(ui, opts), dest, create=1)
2412 hg.repository(hg.remoteui(ui, opts), dest, create=1)
2410
2413
2411 def locate(ui, repo, *pats, **opts):
2414 def locate(ui, repo, *pats, **opts):
2412 """locate files matching specific patterns
2415 """locate files matching specific patterns
2413
2416
2414 Print files under Mercurial control in the working directory whose
2417 Print files under Mercurial control in the working directory whose
2415 names match the given patterns.
2418 names match the given patterns.
2416
2419
2417 By default, this command searches all directories in the working
2420 By default, this command searches all directories in the working
2418 directory. To search just the current directory and its
2421 directory. To search just the current directory and its
2419 subdirectories, use "--include .".
2422 subdirectories, use "--include .".
2420
2423
2421 If no patterns are given to match, this command prints the names
2424 If no patterns are given to match, this command prints the names
2422 of all files under Mercurial control in the working directory.
2425 of all files under Mercurial control in the working directory.
2423
2426
2424 If you want to feed the output of this command into the "xargs"
2427 If you want to feed the output of this command into the "xargs"
2425 command, use the -0 option to both this command and "xargs". This
2428 command, use the -0 option to both this command and "xargs". This
2426 will avoid the problem of "xargs" treating single filenames that
2429 will avoid the problem of "xargs" treating single filenames that
2427 contain whitespace as multiple filenames.
2430 contain whitespace as multiple filenames.
2428
2431
2429 Returns 0 if a match is found, 1 otherwise.
2432 Returns 0 if a match is found, 1 otherwise.
2430 """
2433 """
2431 end = opts.get('print0') and '\0' or '\n'
2434 end = opts.get('print0') and '\0' or '\n'
2432 rev = opts.get('rev') or None
2435 rev = opts.get('rev') or None
2433
2436
2434 ret = 1
2437 ret = 1
2435 m = cmdutil.match(repo, pats, opts, default='relglob')
2438 m = cmdutil.match(repo, pats, opts, default='relglob')
2436 m.bad = lambda x, y: False
2439 m.bad = lambda x, y: False
2437 for abs in repo[rev].walk(m):
2440 for abs in repo[rev].walk(m):
2438 if not rev and abs not in repo.dirstate:
2441 if not rev and abs not in repo.dirstate:
2439 continue
2442 continue
2440 if opts.get('fullpath'):
2443 if opts.get('fullpath'):
2441 ui.write(repo.wjoin(abs), end)
2444 ui.write(repo.wjoin(abs), end)
2442 else:
2445 else:
2443 ui.write(((pats and m.rel(abs)) or abs), end)
2446 ui.write(((pats and m.rel(abs)) or abs), end)
2444 ret = 0
2447 ret = 0
2445
2448
2446 return ret
2449 return ret
2447
2450
2448 def log(ui, repo, *pats, **opts):
2451 def log(ui, repo, *pats, **opts):
2449 """show revision history of entire repository or files
2452 """show revision history of entire repository or files
2450
2453
2451 Print the revision history of the specified files or the entire
2454 Print the revision history of the specified files or the entire
2452 project.
2455 project.
2453
2456
2454 File history is shown without following rename or copy history of
2457 File history is shown without following rename or copy history of
2455 files. Use -f/--follow with a filename to follow history across
2458 files. Use -f/--follow with a filename to follow history across
2456 renames and copies. --follow without a filename will only show
2459 renames and copies. --follow without a filename will only show
2457 ancestors or descendants of the starting revision. --follow-first
2460 ancestors or descendants of the starting revision. --follow-first
2458 only follows the first parent of merge revisions.
2461 only follows the first parent of merge revisions.
2459
2462
2460 If no revision range is specified, the default is tip:0 unless
2463 If no revision range is specified, the default is tip:0 unless
2461 --follow is set, in which case the working directory parent is
2464 --follow is set, in which case the working directory parent is
2462 used as the starting revision. You can specify a revision set for
2465 used as the starting revision. You can specify a revision set for
2463 log, see :hg:`help revsets` for more information.
2466 log, see :hg:`help revsets` for more information.
2464
2467
2465 See :hg:`help dates` for a list of formats valid for -d/--date.
2468 See :hg:`help dates` for a list of formats valid for -d/--date.
2466
2469
2467 By default this command prints revision number and changeset id,
2470 By default this command prints revision number and changeset id,
2468 tags, non-trivial parents, user, date and time, and a summary for
2471 tags, non-trivial parents, user, date and time, and a summary for
2469 each commit. When the -v/--verbose switch is used, the list of
2472 each commit. When the -v/--verbose switch is used, the list of
2470 changed files and full commit message are shown.
2473 changed files and full commit message are shown.
2471
2474
2472 NOTE: log -p/--patch may generate unexpected diff output for merge
2475 NOTE: log -p/--patch may generate unexpected diff output for merge
2473 changesets, as it will only compare the merge changeset against
2476 changesets, as it will only compare the merge changeset against
2474 its first parent. Also, only files different from BOTH parents
2477 its first parent. Also, only files different from BOTH parents
2475 will appear in files:.
2478 will appear in files:.
2476
2479
2477 Returns 0 on success.
2480 Returns 0 on success.
2478 """
2481 """
2479
2482
2480 matchfn = cmdutil.match(repo, pats, opts)
2483 matchfn = cmdutil.match(repo, pats, opts)
2481 limit = cmdutil.loglimit(opts)
2484 limit = cmdutil.loglimit(opts)
2482 count = 0
2485 count = 0
2483
2486
2484 endrev = None
2487 endrev = None
2485 if opts.get('copies') and opts.get('rev'):
2488 if opts.get('copies') and opts.get('rev'):
2486 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2489 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2487
2490
2488 df = False
2491 df = False
2489 if opts["date"]:
2492 if opts["date"]:
2490 df = util.matchdate(opts["date"])
2493 df = util.matchdate(opts["date"])
2491
2494
2492 branches = opts.get('branch', []) + opts.get('only_branch', [])
2495 branches = opts.get('branch', []) + opts.get('only_branch', [])
2493 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2496 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2494
2497
2495 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2498 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2496 def prep(ctx, fns):
2499 def prep(ctx, fns):
2497 rev = ctx.rev()
2500 rev = ctx.rev()
2498 parents = [p for p in repo.changelog.parentrevs(rev)
2501 parents = [p for p in repo.changelog.parentrevs(rev)
2499 if p != nullrev]
2502 if p != nullrev]
2500 if opts.get('no_merges') and len(parents) == 2:
2503 if opts.get('no_merges') and len(parents) == 2:
2501 return
2504 return
2502 if opts.get('only_merges') and len(parents) != 2:
2505 if opts.get('only_merges') and len(parents) != 2:
2503 return
2506 return
2504 if opts.get('branch') and ctx.branch() not in opts['branch']:
2507 if opts.get('branch') and ctx.branch() not in opts['branch']:
2505 return
2508 return
2506 if df and not df(ctx.date()[0]):
2509 if df and not df(ctx.date()[0]):
2507 return
2510 return
2508 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2511 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2509 return
2512 return
2510 if opts.get('keyword'):
2513 if opts.get('keyword'):
2511 for k in [kw.lower() for kw in opts['keyword']]:
2514 for k in [kw.lower() for kw in opts['keyword']]:
2512 if (k in ctx.user().lower() or
2515 if (k in ctx.user().lower() or
2513 k in ctx.description().lower() or
2516 k in ctx.description().lower() or
2514 k in " ".join(ctx.files()).lower()):
2517 k in " ".join(ctx.files()).lower()):
2515 break
2518 break
2516 else:
2519 else:
2517 return
2520 return
2518
2521
2519 copies = None
2522 copies = None
2520 if opts.get('copies') and rev:
2523 if opts.get('copies') and rev:
2521 copies = []
2524 copies = []
2522 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2525 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2523 for fn in ctx.files():
2526 for fn in ctx.files():
2524 rename = getrenamed(fn, rev)
2527 rename = getrenamed(fn, rev)
2525 if rename:
2528 if rename:
2526 copies.append((fn, rename[0]))
2529 copies.append((fn, rename[0]))
2527
2530
2528 revmatchfn = None
2531 revmatchfn = None
2529 if opts.get('patch') or opts.get('stat'):
2532 if opts.get('patch') or opts.get('stat'):
2530 revmatchfn = cmdutil.match(repo, fns, default='path')
2533 revmatchfn = cmdutil.match(repo, fns, default='path')
2531
2534
2532 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2535 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2533
2536
2534 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2537 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2535 if count == limit:
2538 if count == limit:
2536 break
2539 break
2537 if displayer.flush(ctx.rev()):
2540 if displayer.flush(ctx.rev()):
2538 count += 1
2541 count += 1
2539 displayer.close()
2542 displayer.close()
2540
2543
2541 def manifest(ui, repo, node=None, rev=None):
2544 def manifest(ui, repo, node=None, rev=None):
2542 """output the current or given revision of the project manifest
2545 """output the current or given revision of the project manifest
2543
2546
2544 Print a list of version controlled files for the given revision.
2547 Print a list of version controlled files for the given revision.
2545 If no revision is given, the first parent of the working directory
2548 If no revision is given, the first parent of the working directory
2546 is used, or the null revision if no revision is checked out.
2549 is used, or the null revision if no revision is checked out.
2547
2550
2548 With -v, print file permissions, symlink and executable bits.
2551 With -v, print file permissions, symlink and executable bits.
2549 With --debug, print file revision hashes.
2552 With --debug, print file revision hashes.
2550
2553
2551 Returns 0 on success.
2554 Returns 0 on success.
2552 """
2555 """
2553
2556
2554 if rev and node:
2557 if rev and node:
2555 raise util.Abort(_("please specify just one revision"))
2558 raise util.Abort(_("please specify just one revision"))
2556
2559
2557 if not node:
2560 if not node:
2558 node = rev
2561 node = rev
2559
2562
2560 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2563 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2561 ctx = repo[node]
2564 ctx = repo[node]
2562 for f in ctx:
2565 for f in ctx:
2563 if ui.debugflag:
2566 if ui.debugflag:
2564 ui.write("%40s " % hex(ctx.manifest()[f]))
2567 ui.write("%40s " % hex(ctx.manifest()[f]))
2565 if ui.verbose:
2568 if ui.verbose:
2566 ui.write(decor[ctx.flags(f)])
2569 ui.write(decor[ctx.flags(f)])
2567 ui.write("%s\n" % f)
2570 ui.write("%s\n" % f)
2568
2571
2569 def merge(ui, repo, node=None, **opts):
2572 def merge(ui, repo, node=None, **opts):
2570 """merge working directory with another revision
2573 """merge working directory with another revision
2571
2574
2572 The current working directory is updated with all changes made in
2575 The current working directory is updated with all changes made in
2573 the requested revision since the last common predecessor revision.
2576 the requested revision since the last common predecessor revision.
2574
2577
2575 Files that changed between either parent are marked as changed for
2578 Files that changed between either parent are marked as changed for
2576 the next commit and a commit must be performed before any further
2579 the next commit and a commit must be performed before any further
2577 updates to the repository are allowed. The next commit will have
2580 updates to the repository are allowed. The next commit will have
2578 two parents.
2581 two parents.
2579
2582
2580 If no revision is specified, the working directory's parent is a
2583 If no revision is specified, the working directory's parent is a
2581 head revision, and the current branch contains exactly one other
2584 head revision, and the current branch contains exactly one other
2582 head, the other head is merged with by default. Otherwise, an
2585 head, the other head is merged with by default. Otherwise, an
2583 explicit revision with which to merge with must be provided.
2586 explicit revision with which to merge with must be provided.
2584
2587
2585 To undo an uncommitted merge, use :hg:`update --clean .` which
2588 To undo an uncommitted merge, use :hg:`update --clean .` which
2586 will check out a clean copy of the original merge parent, losing
2589 will check out a clean copy of the original merge parent, losing
2587 all changes.
2590 all changes.
2588
2591
2589 Returns 0 on success, 1 if there are unresolved files.
2592 Returns 0 on success, 1 if there are unresolved files.
2590 """
2593 """
2591
2594
2592 if opts.get('rev') and node:
2595 if opts.get('rev') and node:
2593 raise util.Abort(_("please specify just one revision"))
2596 raise util.Abort(_("please specify just one revision"))
2594 if not node:
2597 if not node:
2595 node = opts.get('rev')
2598 node = opts.get('rev')
2596
2599
2597 if not node:
2600 if not node:
2598 branch = repo.changectx(None).branch()
2601 branch = repo.changectx(None).branch()
2599 bheads = repo.branchheads(branch)
2602 bheads = repo.branchheads(branch)
2600 if len(bheads) > 2:
2603 if len(bheads) > 2:
2601 raise util.Abort(_(
2604 raise util.Abort(_(
2602 'branch \'%s\' has %d heads - '
2605 'branch \'%s\' has %d heads - '
2603 'please merge with an explicit rev\n'
2606 'please merge with an explicit rev\n'
2604 '(run \'hg heads .\' to see heads)')
2607 '(run \'hg heads .\' to see heads)')
2605 % (branch, len(bheads)))
2608 % (branch, len(bheads)))
2606
2609
2607 parent = repo.dirstate.parents()[0]
2610 parent = repo.dirstate.parents()[0]
2608 if len(bheads) == 1:
2611 if len(bheads) == 1:
2609 if len(repo.heads()) > 1:
2612 if len(repo.heads()) > 1:
2610 raise util.Abort(_(
2613 raise util.Abort(_(
2611 'branch \'%s\' has one head - '
2614 'branch \'%s\' has one head - '
2612 'please merge with an explicit rev\n'
2615 'please merge with an explicit rev\n'
2613 '(run \'hg heads\' to see all heads)')
2616 '(run \'hg heads\' to see all heads)')
2614 % branch)
2617 % branch)
2615 msg = _('there is nothing to merge')
2618 msg = _('there is nothing to merge')
2616 if parent != repo.lookup(repo[None].branch()):
2619 if parent != repo.lookup(repo[None].branch()):
2617 msg = _('%s - use "hg update" instead') % msg
2620 msg = _('%s - use "hg update" instead') % msg
2618 raise util.Abort(msg)
2621 raise util.Abort(msg)
2619
2622
2620 if parent not in bheads:
2623 if parent not in bheads:
2621 raise util.Abort(_('working dir not at a head rev - '
2624 raise util.Abort(_('working dir not at a head rev - '
2622 'use "hg update" or merge with an explicit rev'))
2625 'use "hg update" or merge with an explicit rev'))
2623 node = parent == bheads[0] and bheads[-1] or bheads[0]
2626 node = parent == bheads[0] and bheads[-1] or bheads[0]
2624
2627
2625 if opts.get('preview'):
2628 if opts.get('preview'):
2626 # find nodes that are ancestors of p2 but not of p1
2629 # find nodes that are ancestors of p2 but not of p1
2627 p1 = repo.lookup('.')
2630 p1 = repo.lookup('.')
2628 p2 = repo.lookup(node)
2631 p2 = repo.lookup(node)
2629 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2632 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2630
2633
2631 displayer = cmdutil.show_changeset(ui, repo, opts)
2634 displayer = cmdutil.show_changeset(ui, repo, opts)
2632 for node in nodes:
2635 for node in nodes:
2633 displayer.show(repo[node])
2636 displayer.show(repo[node])
2634 displayer.close()
2637 displayer.close()
2635 return 0
2638 return 0
2636
2639
2637 return hg.merge(repo, node, force=opts.get('force'))
2640 return hg.merge(repo, node, force=opts.get('force'))
2638
2641
2639 def outgoing(ui, repo, dest=None, **opts):
2642 def outgoing(ui, repo, dest=None, **opts):
2640 """show changesets not found in the destination
2643 """show changesets not found in the destination
2641
2644
2642 Show changesets not found in the specified destination repository
2645 Show changesets not found in the specified destination repository
2643 or the default push location. These are the changesets that would
2646 or the default push location. These are the changesets that would
2644 be pushed if a push was requested.
2647 be pushed if a push was requested.
2645
2648
2646 See pull for details of valid destination formats.
2649 See pull for details of valid destination formats.
2647
2650
2648 Returns 0 if there are outgoing changes, 1 otherwise.
2651 Returns 0 if there are outgoing changes, 1 otherwise.
2649 """
2652 """
2650 limit = cmdutil.loglimit(opts)
2653 limit = cmdutil.loglimit(opts)
2651 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2654 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2652 dest, branches = hg.parseurl(dest, opts.get('branch'))
2655 dest, branches = hg.parseurl(dest, opts.get('branch'))
2653 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2656 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2654 if revs:
2657 if revs:
2655 revs = [repo.lookup(rev) for rev in revs]
2658 revs = [repo.lookup(rev) for rev in revs]
2656
2659
2657 other = hg.repository(hg.remoteui(repo, opts), dest)
2660 other = hg.repository(hg.remoteui(repo, opts), dest)
2658 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2661 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2659 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
2662 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
2660 if not o:
2663 if not o:
2661 ui.status(_("no changes found\n"))
2664 ui.status(_("no changes found\n"))
2662 return 1
2665 return 1
2663 o = repo.changelog.nodesbetween(o, revs)[0]
2666 o = repo.changelog.nodesbetween(o, revs)[0]
2664 if opts.get('newest_first'):
2667 if opts.get('newest_first'):
2665 o.reverse()
2668 o.reverse()
2666 displayer = cmdutil.show_changeset(ui, repo, opts)
2669 displayer = cmdutil.show_changeset(ui, repo, opts)
2667 count = 0
2670 count = 0
2668 for n in o:
2671 for n in o:
2669 if limit is not None and count >= limit:
2672 if limit is not None and count >= limit:
2670 break
2673 break
2671 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2674 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2672 if opts.get('no_merges') and len(parents) == 2:
2675 if opts.get('no_merges') and len(parents) == 2:
2673 continue
2676 continue
2674 count += 1
2677 count += 1
2675 displayer.show(repo[n])
2678 displayer.show(repo[n])
2676 displayer.close()
2679 displayer.close()
2677
2680
2678 def parents(ui, repo, file_=None, **opts):
2681 def parents(ui, repo, file_=None, **opts):
2679 """show the parents of the working directory or revision
2682 """show the parents of the working directory or revision
2680
2683
2681 Print the working directory's parent revisions. If a revision is
2684 Print the working directory's parent revisions. If a revision is
2682 given via -r/--rev, the parent of that revision will be printed.
2685 given via -r/--rev, the parent of that revision will be printed.
2683 If a file argument is given, the revision in which the file was
2686 If a file argument is given, the revision in which the file was
2684 last changed (before the working directory revision or the
2687 last changed (before the working directory revision or the
2685 argument to --rev if given) is printed.
2688 argument to --rev if given) is printed.
2686
2689
2687 Returns 0 on success.
2690 Returns 0 on success.
2688 """
2691 """
2689 rev = opts.get('rev')
2692 rev = opts.get('rev')
2690 if rev:
2693 if rev:
2691 ctx = repo[rev]
2694 ctx = repo[rev]
2692 else:
2695 else:
2693 ctx = repo[None]
2696 ctx = repo[None]
2694
2697
2695 if file_:
2698 if file_:
2696 m = cmdutil.match(repo, (file_,), opts)
2699 m = cmdutil.match(repo, (file_,), opts)
2697 if m.anypats() or len(m.files()) != 1:
2700 if m.anypats() or len(m.files()) != 1:
2698 raise util.Abort(_('can only specify an explicit filename'))
2701 raise util.Abort(_('can only specify an explicit filename'))
2699 file_ = m.files()[0]
2702 file_ = m.files()[0]
2700 filenodes = []
2703 filenodes = []
2701 for cp in ctx.parents():
2704 for cp in ctx.parents():
2702 if not cp:
2705 if not cp:
2703 continue
2706 continue
2704 try:
2707 try:
2705 filenodes.append(cp.filenode(file_))
2708 filenodes.append(cp.filenode(file_))
2706 except error.LookupError:
2709 except error.LookupError:
2707 pass
2710 pass
2708 if not filenodes:
2711 if not filenodes:
2709 raise util.Abort(_("'%s' not found in manifest!") % file_)
2712 raise util.Abort(_("'%s' not found in manifest!") % file_)
2710 fl = repo.file(file_)
2713 fl = repo.file(file_)
2711 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2714 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2712 else:
2715 else:
2713 p = [cp.node() for cp in ctx.parents()]
2716 p = [cp.node() for cp in ctx.parents()]
2714
2717
2715 displayer = cmdutil.show_changeset(ui, repo, opts)
2718 displayer = cmdutil.show_changeset(ui, repo, opts)
2716 for n in p:
2719 for n in p:
2717 if n != nullid:
2720 if n != nullid:
2718 displayer.show(repo[n])
2721 displayer.show(repo[n])
2719 displayer.close()
2722 displayer.close()
2720
2723
2721 def paths(ui, repo, search=None):
2724 def paths(ui, repo, search=None):
2722 """show aliases for remote repositories
2725 """show aliases for remote repositories
2723
2726
2724 Show definition of symbolic path name NAME. If no name is given,
2727 Show definition of symbolic path name NAME. If no name is given,
2725 show definition of all available names.
2728 show definition of all available names.
2726
2729
2727 Path names are defined in the [paths] section of
2730 Path names are defined in the [paths] section of your
2728 ``/etc/mercurial/hgrc`` and ``$HOME/.hgrc``. If run inside a
2731 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2729 repository, ``.hg/hgrc`` is used, too.
2732 repository, ``.hg/hgrc`` is used, too.
2730
2733
2731 The path names ``default`` and ``default-push`` have a special
2734 The path names ``default`` and ``default-push`` have a special
2732 meaning. When performing a push or pull operation, they are used
2735 meaning. When performing a push or pull operation, they are used
2733 as fallbacks if no location is specified on the command-line.
2736 as fallbacks if no location is specified on the command-line.
2734 When ``default-push`` is set, it will be used for push and
2737 When ``default-push`` is set, it will be used for push and
2735 ``default`` will be used for pull; otherwise ``default`` is used
2738 ``default`` will be used for pull; otherwise ``default`` is used
2736 as the fallback for both. When cloning a repository, the clone
2739 as the fallback for both. When cloning a repository, the clone
2737 source is written as ``default`` in ``.hg/hgrc``. Note that
2740 source is written as ``default`` in ``.hg/hgrc``. Note that
2738 ``default`` and ``default-push`` apply to all inbound (e.g.
2741 ``default`` and ``default-push`` apply to all inbound (e.g.
2739 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2742 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2740 :hg:`bundle`) operations.
2743 :hg:`bundle`) operations.
2741
2744
2742 See :hg:`help urls` for more information.
2745 See :hg:`help urls` for more information.
2743
2746
2744 Returns 0 on success.
2747 Returns 0 on success.
2745 """
2748 """
2746 if search:
2749 if search:
2747 for name, path in ui.configitems("paths"):
2750 for name, path in ui.configitems("paths"):
2748 if name == search:
2751 if name == search:
2749 ui.write("%s\n" % url.hidepassword(path))
2752 ui.write("%s\n" % url.hidepassword(path))
2750 return
2753 return
2751 ui.warn(_("not found!\n"))
2754 ui.warn(_("not found!\n"))
2752 return 1
2755 return 1
2753 else:
2756 else:
2754 for name, path in ui.configitems("paths"):
2757 for name, path in ui.configitems("paths"):
2755 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2758 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2756
2759
2757 def postincoming(ui, repo, modheads, optupdate, checkout):
2760 def postincoming(ui, repo, modheads, optupdate, checkout):
2758 if modheads == 0:
2761 if modheads == 0:
2759 return
2762 return
2760 if optupdate:
2763 if optupdate:
2761 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2764 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2762 return hg.update(repo, checkout)
2765 return hg.update(repo, checkout)
2763 else:
2766 else:
2764 ui.status(_("not updating, since new heads added\n"))
2767 ui.status(_("not updating, since new heads added\n"))
2765 if modheads > 1:
2768 if modheads > 1:
2766 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2769 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2767 else:
2770 else:
2768 ui.status(_("(run 'hg update' to get a working copy)\n"))
2771 ui.status(_("(run 'hg update' to get a working copy)\n"))
2769
2772
2770 def pull(ui, repo, source="default", **opts):
2773 def pull(ui, repo, source="default", **opts):
2771 """pull changes from the specified source
2774 """pull changes from the specified source
2772
2775
2773 Pull changes from a remote repository to a local one.
2776 Pull changes from a remote repository to a local one.
2774
2777
2775 This finds all changes from the repository at the specified path
2778 This finds all changes from the repository at the specified path
2776 or URL and adds them to a local repository (the current one unless
2779 or URL and adds them to a local repository (the current one unless
2777 -R is specified). By default, this does not update the copy of the
2780 -R is specified). By default, this does not update the copy of the
2778 project in the working directory.
2781 project in the working directory.
2779
2782
2780 Use :hg:`incoming` if you want to see what would have been added
2783 Use :hg:`incoming` if you want to see what would have been added
2781 by a pull at the time you issued this command. If you then decide
2784 by a pull at the time you issued this command. If you then decide
2782 to add those changes to the repository, you should use :hg:`pull
2785 to add those changes to the repository, you should use :hg:`pull
2783 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2786 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2784
2787
2785 If SOURCE is omitted, the 'default' path will be used.
2788 If SOURCE is omitted, the 'default' path will be used.
2786 See :hg:`help urls` for more information.
2789 See :hg:`help urls` for more information.
2787
2790
2788 Returns 0 on success, 1 if an update had unresolved files.
2791 Returns 0 on success, 1 if an update had unresolved files.
2789 """
2792 """
2790 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2793 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2791 other = hg.repository(hg.remoteui(repo, opts), source)
2794 other = hg.repository(hg.remoteui(repo, opts), source)
2792 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2795 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2793 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2796 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2794 if revs:
2797 if revs:
2795 try:
2798 try:
2796 revs = [other.lookup(rev) for rev in revs]
2799 revs = [other.lookup(rev) for rev in revs]
2797 except error.CapabilityError:
2800 except error.CapabilityError:
2798 err = _("Other repository doesn't support revision lookup, "
2801 err = _("Other repository doesn't support revision lookup, "
2799 "so a rev cannot be specified.")
2802 "so a rev cannot be specified.")
2800 raise util.Abort(err)
2803 raise util.Abort(err)
2801
2804
2802 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2805 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2803 if checkout:
2806 if checkout:
2804 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2807 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2805 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2808 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2806
2809
2807 def push(ui, repo, dest=None, **opts):
2810 def push(ui, repo, dest=None, **opts):
2808 """push changes to the specified destination
2811 """push changes to the specified destination
2809
2812
2810 Push changesets from the local repository to the specified
2813 Push changesets from the local repository to the specified
2811 destination.
2814 destination.
2812
2815
2813 This operation is symmetrical to pull: it is identical to a pull
2816 This operation is symmetrical to pull: it is identical to a pull
2814 in the destination repository from the current one.
2817 in the destination repository from the current one.
2815
2818
2816 By default, push will not allow creation of new heads at the
2819 By default, push will not allow creation of new heads at the
2817 destination, since multiple heads would make it unclear which head
2820 destination, since multiple heads would make it unclear which head
2818 to use. In this situation, it is recommended to pull and merge
2821 to use. In this situation, it is recommended to pull and merge
2819 before pushing.
2822 before pushing.
2820
2823
2821 Use --new-branch if you want to allow push to create a new named
2824 Use --new-branch if you want to allow push to create a new named
2822 branch that is not present at the destination. This allows you to
2825 branch that is not present at the destination. This allows you to
2823 only create a new branch without forcing other changes.
2826 only create a new branch without forcing other changes.
2824
2827
2825 Use -f/--force to override the default behavior and push all
2828 Use -f/--force to override the default behavior and push all
2826 changesets on all branches.
2829 changesets on all branches.
2827
2830
2828 If -r/--rev is used, the specified revision and all its ancestors
2831 If -r/--rev is used, the specified revision and all its ancestors
2829 will be pushed to the remote repository.
2832 will be pushed to the remote repository.
2830
2833
2831 Please see :hg:`help urls` for important details about ``ssh://``
2834 Please see :hg:`help urls` for important details about ``ssh://``
2832 URLs. If DESTINATION is omitted, a default path will be used.
2835 URLs. If DESTINATION is omitted, a default path will be used.
2833
2836
2834 Returns 0 if push was successful, 1 if nothing to push.
2837 Returns 0 if push was successful, 1 if nothing to push.
2835 """
2838 """
2836 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2837 dest, branches = hg.parseurl(dest, opts.get('branch'))
2840 dest, branches = hg.parseurl(dest, opts.get('branch'))
2838 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2841 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2839 other = hg.repository(hg.remoteui(repo, opts), dest)
2842 other = hg.repository(hg.remoteui(repo, opts), dest)
2840 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2843 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2841 if revs:
2844 if revs:
2842 revs = [repo.lookup(rev) for rev in revs]
2845 revs = [repo.lookup(rev) for rev in revs]
2843
2846
2844 # push subrepos depth-first for coherent ordering
2847 # push subrepos depth-first for coherent ordering
2845 c = repo['']
2848 c = repo['']
2846 subs = c.substate # only repos that are committed
2849 subs = c.substate # only repos that are committed
2847 for s in sorted(subs):
2850 for s in sorted(subs):
2848 if not c.sub(s).push(opts.get('force')):
2851 if not c.sub(s).push(opts.get('force')):
2849 return False
2852 return False
2850
2853
2851 r = repo.push(other, opts.get('force'), revs=revs,
2854 r = repo.push(other, opts.get('force'), revs=revs,
2852 newbranch=opts.get('new_branch'))
2855 newbranch=opts.get('new_branch'))
2853 return r == 0
2856 return r == 0
2854
2857
2855 def recover(ui, repo):
2858 def recover(ui, repo):
2856 """roll back an interrupted transaction
2859 """roll back an interrupted transaction
2857
2860
2858 Recover from an interrupted commit or pull.
2861 Recover from an interrupted commit or pull.
2859
2862
2860 This command tries to fix the repository status after an
2863 This command tries to fix the repository status after an
2861 interrupted operation. It should only be necessary when Mercurial
2864 interrupted operation. It should only be necessary when Mercurial
2862 suggests it.
2865 suggests it.
2863
2866
2864 Returns 0 if successful, 1 if nothing to recover or verify fails.
2867 Returns 0 if successful, 1 if nothing to recover or verify fails.
2865 """
2868 """
2866 if repo.recover():
2869 if repo.recover():
2867 return hg.verify(repo)
2870 return hg.verify(repo)
2868 return 1
2871 return 1
2869
2872
2870 def remove(ui, repo, *pats, **opts):
2873 def remove(ui, repo, *pats, **opts):
2871 """remove the specified files on the next commit
2874 """remove the specified files on the next commit
2872
2875
2873 Schedule the indicated files for removal from the repository.
2876 Schedule the indicated files for removal from the repository.
2874
2877
2875 This only removes files from the current branch, not from the
2878 This only removes files from the current branch, not from the
2876 entire project history. -A/--after can be used to remove only
2879 entire project history. -A/--after can be used to remove only
2877 files that have already been deleted, -f/--force can be used to
2880 files that have already been deleted, -f/--force can be used to
2878 force deletion, and -Af can be used to remove files from the next
2881 force deletion, and -Af can be used to remove files from the next
2879 revision without deleting them from the working directory.
2882 revision without deleting them from the working directory.
2880
2883
2881 The following table details the behavior of remove for different
2884 The following table details the behavior of remove for different
2882 file states (columns) and option combinations (rows). The file
2885 file states (columns) and option combinations (rows). The file
2883 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2886 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2884 reported by :hg:`status`). The actions are Warn, Remove (from
2887 reported by :hg:`status`). The actions are Warn, Remove (from
2885 branch) and Delete (from disk)::
2888 branch) and Delete (from disk)::
2886
2889
2887 A C M !
2890 A C M !
2888 none W RD W R
2891 none W RD W R
2889 -f R RD RD R
2892 -f R RD RD R
2890 -A W W W R
2893 -A W W W R
2891 -Af R R R R
2894 -Af R R R R
2892
2895
2893 This command schedules the files to be removed at the next commit.
2896 This command schedules the files to be removed at the next commit.
2894 To undo a remove before that, see :hg:`revert`.
2897 To undo a remove before that, see :hg:`revert`.
2895
2898
2896 Returns 0 on success, 1 if any warnings encountered.
2899 Returns 0 on success, 1 if any warnings encountered.
2897 """
2900 """
2898
2901
2899 ret = 0
2902 ret = 0
2900 after, force = opts.get('after'), opts.get('force')
2903 after, force = opts.get('after'), opts.get('force')
2901 if not pats and not after:
2904 if not pats and not after:
2902 raise util.Abort(_('no files specified'))
2905 raise util.Abort(_('no files specified'))
2903
2906
2904 m = cmdutil.match(repo, pats, opts)
2907 m = cmdutil.match(repo, pats, opts)
2905 s = repo.status(match=m, clean=True)
2908 s = repo.status(match=m, clean=True)
2906 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2909 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2907
2910
2908 for f in m.files():
2911 for f in m.files():
2909 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2912 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2910 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2913 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2911 ret = 1
2914 ret = 1
2912
2915
2913 def warn(files, reason):
2916 def warn(files, reason):
2914 for f in files:
2917 for f in files:
2915 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2918 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2916 % (m.rel(f), reason))
2919 % (m.rel(f), reason))
2917 ret = 1
2920 ret = 1
2918
2921
2919 if force:
2922 if force:
2920 remove, forget = modified + deleted + clean, added
2923 remove, forget = modified + deleted + clean, added
2921 elif after:
2924 elif after:
2922 remove, forget = deleted, []
2925 remove, forget = deleted, []
2923 warn(modified + added + clean, _('still exists'))
2926 warn(modified + added + clean, _('still exists'))
2924 else:
2927 else:
2925 remove, forget = deleted + clean, []
2928 remove, forget = deleted + clean, []
2926 warn(modified, _('is modified'))
2929 warn(modified, _('is modified'))
2927 warn(added, _('has been marked for add'))
2930 warn(added, _('has been marked for add'))
2928
2931
2929 for f in sorted(remove + forget):
2932 for f in sorted(remove + forget):
2930 if ui.verbose or not m.exact(f):
2933 if ui.verbose or not m.exact(f):
2931 ui.status(_('removing %s\n') % m.rel(f))
2934 ui.status(_('removing %s\n') % m.rel(f))
2932
2935
2933 repo[None].forget(forget)
2936 repo[None].forget(forget)
2934 repo[None].remove(remove, unlink=not after)
2937 repo[None].remove(remove, unlink=not after)
2935 return ret
2938 return ret
2936
2939
2937 def rename(ui, repo, *pats, **opts):
2940 def rename(ui, repo, *pats, **opts):
2938 """rename files; equivalent of copy + remove
2941 """rename files; equivalent of copy + remove
2939
2942
2940 Mark dest as copies of sources; mark sources for deletion. If dest
2943 Mark dest as copies of sources; mark sources for deletion. If dest
2941 is a directory, copies are put in that directory. If dest is a
2944 is a directory, copies are put in that directory. If dest is a
2942 file, there can only be one source.
2945 file, there can only be one source.
2943
2946
2944 By default, this command copies the contents of files as they
2947 By default, this command copies the contents of files as they
2945 exist in the working directory. If invoked with -A/--after, the
2948 exist in the working directory. If invoked with -A/--after, the
2946 operation is recorded, but no copying is performed.
2949 operation is recorded, but no copying is performed.
2947
2950
2948 This command takes effect at the next commit. To undo a rename
2951 This command takes effect at the next commit. To undo a rename
2949 before that, see :hg:`revert`.
2952 before that, see :hg:`revert`.
2950
2953
2951 Returns 0 on success, 1 if errors are encountered.
2954 Returns 0 on success, 1 if errors are encountered.
2952 """
2955 """
2953 wlock = repo.wlock(False)
2956 wlock = repo.wlock(False)
2954 try:
2957 try:
2955 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2958 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2956 finally:
2959 finally:
2957 wlock.release()
2960 wlock.release()
2958
2961
2959 def resolve(ui, repo, *pats, **opts):
2962 def resolve(ui, repo, *pats, **opts):
2960 """redo merges or set/view the merge status of files
2963 """redo merges or set/view the merge status of files
2961
2964
2962 Merges with unresolved conflicts are often the result of
2965 Merges with unresolved conflicts are often the result of
2963 non-interactive merging using the ``internal:merge`` hgrc setting,
2966 non-interactive merging using the ``internal:merge`` configuration
2964 or a command-line merge tool like ``diff3``. The resolve command
2967 setting, or a command-line merge tool like ``diff3``. The resolve
2965 is used to manage the files involved in a merge, after :hg:`merge`
2968 command is used to manage the files involved in a merge, after
2966 has been run, and before :hg:`commit` is run (i.e. the working
2969 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2967 directory must have two parents).
2970 working directory must have two parents).
2968
2971
2969 The resolve command can be used in the following ways:
2972 The resolve command can be used in the following ways:
2970
2973
2971 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2974 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2972 discarding any previous merge attempts. Re-merging is not
2975 discarding any previous merge attempts. Re-merging is not
2973 performed for files already marked as resolved. Use ``--all/-a``
2976 performed for files already marked as resolved. Use ``--all/-a``
2974 to selects all unresolved files.
2977 to selects all unresolved files.
2975
2978
2976 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2979 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2977 (e.g. after having manually fixed-up the files). The default is
2980 (e.g. after having manually fixed-up the files). The default is
2978 to mark all unresolved files.
2981 to mark all unresolved files.
2979
2982
2980 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2983 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2981 default is to mark all resolved files.
2984 default is to mark all resolved files.
2982
2985
2983 - :hg:`resolve -l`: list files which had or still have conflicts.
2986 - :hg:`resolve -l`: list files which had or still have conflicts.
2984 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2987 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2985
2988
2986 Note that Mercurial will not let you commit files with unresolved
2989 Note that Mercurial will not let you commit files with unresolved
2987 merge conflicts. You must use :hg:`resolve -m ...` before you can
2990 merge conflicts. You must use :hg:`resolve -m ...` before you can
2988 commit after a conflicting merge.
2991 commit after a conflicting merge.
2989
2992
2990 Returns 0 on success, 1 if any files fail a resolve attempt.
2993 Returns 0 on success, 1 if any files fail a resolve attempt.
2991 """
2994 """
2992
2995
2993 all, mark, unmark, show, nostatus = \
2996 all, mark, unmark, show, nostatus = \
2994 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2997 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2995
2998
2996 if (show and (mark or unmark)) or (mark and unmark):
2999 if (show and (mark or unmark)) or (mark and unmark):
2997 raise util.Abort(_("too many options specified"))
3000 raise util.Abort(_("too many options specified"))
2998 if pats and all:
3001 if pats and all:
2999 raise util.Abort(_("can't specify --all and patterns"))
3002 raise util.Abort(_("can't specify --all and patterns"))
3000 if not (all or pats or show or mark or unmark):
3003 if not (all or pats or show or mark or unmark):
3001 raise util.Abort(_('no files or directories specified; '
3004 raise util.Abort(_('no files or directories specified; '
3002 'use --all to remerge all files'))
3005 'use --all to remerge all files'))
3003
3006
3004 ms = mergemod.mergestate(repo)
3007 ms = mergemod.mergestate(repo)
3005 m = cmdutil.match(repo, pats, opts)
3008 m = cmdutil.match(repo, pats, opts)
3006 ret = 0
3009 ret = 0
3007
3010
3008 for f in ms:
3011 for f in ms:
3009 if m(f):
3012 if m(f):
3010 if show:
3013 if show:
3011 if nostatus:
3014 if nostatus:
3012 ui.write("%s\n" % f)
3015 ui.write("%s\n" % f)
3013 else:
3016 else:
3014 ui.write("%s %s\n" % (ms[f].upper(), f),
3017 ui.write("%s %s\n" % (ms[f].upper(), f),
3015 label='resolve.' +
3018 label='resolve.' +
3016 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3019 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3017 elif mark:
3020 elif mark:
3018 ms.mark(f, "r")
3021 ms.mark(f, "r")
3019 elif unmark:
3022 elif unmark:
3020 ms.mark(f, "u")
3023 ms.mark(f, "u")
3021 else:
3024 else:
3022 wctx = repo[None]
3025 wctx = repo[None]
3023 mctx = wctx.parents()[-1]
3026 mctx = wctx.parents()[-1]
3024
3027
3025 # backup pre-resolve (merge uses .orig for its own purposes)
3028 # backup pre-resolve (merge uses .orig for its own purposes)
3026 a = repo.wjoin(f)
3029 a = repo.wjoin(f)
3027 util.copyfile(a, a + ".resolve")
3030 util.copyfile(a, a + ".resolve")
3028
3031
3029 # resolve file
3032 # resolve file
3030 if ms.resolve(f, wctx, mctx):
3033 if ms.resolve(f, wctx, mctx):
3031 ret = 1
3034 ret = 1
3032
3035
3033 # replace filemerge's .orig file with our resolve file
3036 # replace filemerge's .orig file with our resolve file
3034 util.rename(a + ".resolve", a + ".orig")
3037 util.rename(a + ".resolve", a + ".orig")
3035 return ret
3038 return ret
3036
3039
3037 def revert(ui, repo, *pats, **opts):
3040 def revert(ui, repo, *pats, **opts):
3038 """restore individual files or directories to an earlier state
3041 """restore individual files or directories to an earlier state
3039
3042
3040 NOTE: This command is most likely not what you are looking for. revert
3043 NOTE: This command is most likely not what you are looking for. revert
3041 will partially overwrite content in the working directory without changing
3044 will partially overwrite content in the working directory without changing
3042 the working directory parents. Use :hg:`update -r rev` to check out earlier
3045 the working directory parents. Use :hg:`update -r rev` to check out earlier
3043 revisions, or :hg:`update --clean .` to undo a merge which has added
3046 revisions, or :hg:`update --clean .` to undo a merge which has added
3044 another parent.
3047 another parent.
3045
3048
3046 With no revision specified, revert the named files or directories
3049 With no revision specified, revert the named files or directories
3047 to the contents they had in the parent of the working directory.
3050 to the contents they had in the parent of the working directory.
3048 This restores the contents of the affected files to an unmodified
3051 This restores the contents of the affected files to an unmodified
3049 state and unschedules adds, removes, copies, and renames. If the
3052 state and unschedules adds, removes, copies, and renames. If the
3050 working directory has two parents, you must explicitly specify a
3053 working directory has two parents, you must explicitly specify a
3051 revision.
3054 revision.
3052
3055
3053 Using the -r/--rev option, revert the given files or directories
3056 Using the -r/--rev option, revert the given files or directories
3054 to their contents as of a specific revision. This can be helpful
3057 to their contents as of a specific revision. This can be helpful
3055 to "roll back" some or all of an earlier change. See :hg:`help
3058 to "roll back" some or all of an earlier change. See :hg:`help
3056 dates` for a list of formats valid for -d/--date.
3059 dates` for a list of formats valid for -d/--date.
3057
3060
3058 Revert modifies the working directory. It does not commit any
3061 Revert modifies the working directory. It does not commit any
3059 changes, or change the parent of the working directory. If you
3062 changes, or change the parent of the working directory. If you
3060 revert to a revision other than the parent of the working
3063 revert to a revision other than the parent of the working
3061 directory, the reverted files will thus appear modified
3064 directory, the reverted files will thus appear modified
3062 afterwards.
3065 afterwards.
3063
3066
3064 If a file has been deleted, it is restored. If the executable mode
3067 If a file has been deleted, it is restored. If the executable mode
3065 of a file was changed, it is reset.
3068 of a file was changed, it is reset.
3066
3069
3067 If names are given, all files matching the names are reverted.
3070 If names are given, all files matching the names are reverted.
3068 If no arguments are given, no files are reverted.
3071 If no arguments are given, no files are reverted.
3069
3072
3070 Modified files are saved with a .orig suffix before reverting.
3073 Modified files are saved with a .orig suffix before reverting.
3071 To disable these backups, use --no-backup.
3074 To disable these backups, use --no-backup.
3072
3075
3073 Returns 0 on success.
3076 Returns 0 on success.
3074 """
3077 """
3075
3078
3076 if opts.get("date"):
3079 if opts.get("date"):
3077 if opts.get("rev"):
3080 if opts.get("rev"):
3078 raise util.Abort(_("you can't specify a revision and a date"))
3081 raise util.Abort(_("you can't specify a revision and a date"))
3079 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3082 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3080
3083
3081 if not pats and not opts.get('all'):
3084 if not pats and not opts.get('all'):
3082 raise util.Abort(_('no files or directories specified; '
3085 raise util.Abort(_('no files or directories specified; '
3083 'use --all to revert the whole repo'))
3086 'use --all to revert the whole repo'))
3084
3087
3085 parent, p2 = repo.dirstate.parents()
3088 parent, p2 = repo.dirstate.parents()
3086 if not opts.get('rev') and p2 != nullid:
3089 if not opts.get('rev') and p2 != nullid:
3087 raise util.Abort(_('uncommitted merge - please provide a '
3090 raise util.Abort(_('uncommitted merge - please provide a '
3088 'specific revision'))
3091 'specific revision'))
3089 ctx = repo[opts.get('rev')]
3092 ctx = repo[opts.get('rev')]
3090 node = ctx.node()
3093 node = ctx.node()
3091 mf = ctx.manifest()
3094 mf = ctx.manifest()
3092 if node == parent:
3095 if node == parent:
3093 pmf = mf
3096 pmf = mf
3094 else:
3097 else:
3095 pmf = None
3098 pmf = None
3096
3099
3097 # need all matching names in dirstate and manifest of target rev,
3100 # need all matching names in dirstate and manifest of target rev,
3098 # so have to walk both. do not print errors if files exist in one
3101 # so have to walk both. do not print errors if files exist in one
3099 # but not other.
3102 # but not other.
3100
3103
3101 names = {}
3104 names = {}
3102
3105
3103 wlock = repo.wlock()
3106 wlock = repo.wlock()
3104 try:
3107 try:
3105 # walk dirstate.
3108 # walk dirstate.
3106
3109
3107 m = cmdutil.match(repo, pats, opts)
3110 m = cmdutil.match(repo, pats, opts)
3108 m.bad = lambda x, y: False
3111 m.bad = lambda x, y: False
3109 for abs in repo.walk(m):
3112 for abs in repo.walk(m):
3110 names[abs] = m.rel(abs), m.exact(abs)
3113 names[abs] = m.rel(abs), m.exact(abs)
3111
3114
3112 # walk target manifest.
3115 # walk target manifest.
3113
3116
3114 def badfn(path, msg):
3117 def badfn(path, msg):
3115 if path in names:
3118 if path in names:
3116 return
3119 return
3117 path_ = path + '/'
3120 path_ = path + '/'
3118 for f in names:
3121 for f in names:
3119 if f.startswith(path_):
3122 if f.startswith(path_):
3120 return
3123 return
3121 ui.warn("%s: %s\n" % (m.rel(path), msg))
3124 ui.warn("%s: %s\n" % (m.rel(path), msg))
3122
3125
3123 m = cmdutil.match(repo, pats, opts)
3126 m = cmdutil.match(repo, pats, opts)
3124 m.bad = badfn
3127 m.bad = badfn
3125 for abs in repo[node].walk(m):
3128 for abs in repo[node].walk(m):
3126 if abs not in names:
3129 if abs not in names:
3127 names[abs] = m.rel(abs), m.exact(abs)
3130 names[abs] = m.rel(abs), m.exact(abs)
3128
3131
3129 m = cmdutil.matchfiles(repo, names)
3132 m = cmdutil.matchfiles(repo, names)
3130 changes = repo.status(match=m)[:4]
3133 changes = repo.status(match=m)[:4]
3131 modified, added, removed, deleted = map(set, changes)
3134 modified, added, removed, deleted = map(set, changes)
3132
3135
3133 # if f is a rename, also revert the source
3136 # if f is a rename, also revert the source
3134 cwd = repo.getcwd()
3137 cwd = repo.getcwd()
3135 for f in added:
3138 for f in added:
3136 src = repo.dirstate.copied(f)
3139 src = repo.dirstate.copied(f)
3137 if src and src not in names and repo.dirstate[src] == 'r':
3140 if src and src not in names and repo.dirstate[src] == 'r':
3138 removed.add(src)
3141 removed.add(src)
3139 names[src] = (repo.pathto(src, cwd), True)
3142 names[src] = (repo.pathto(src, cwd), True)
3140
3143
3141 def removeforget(abs):
3144 def removeforget(abs):
3142 if repo.dirstate[abs] == 'a':
3145 if repo.dirstate[abs] == 'a':
3143 return _('forgetting %s\n')
3146 return _('forgetting %s\n')
3144 return _('removing %s\n')
3147 return _('removing %s\n')
3145
3148
3146 revert = ([], _('reverting %s\n'))
3149 revert = ([], _('reverting %s\n'))
3147 add = ([], _('adding %s\n'))
3150 add = ([], _('adding %s\n'))
3148 remove = ([], removeforget)
3151 remove = ([], removeforget)
3149 undelete = ([], _('undeleting %s\n'))
3152 undelete = ([], _('undeleting %s\n'))
3150
3153
3151 disptable = (
3154 disptable = (
3152 # dispatch table:
3155 # dispatch table:
3153 # file state
3156 # file state
3154 # action if in target manifest
3157 # action if in target manifest
3155 # action if not in target manifest
3158 # action if not in target manifest
3156 # make backup if in target manifest
3159 # make backup if in target manifest
3157 # make backup if not in target manifest
3160 # make backup if not in target manifest
3158 (modified, revert, remove, True, True),
3161 (modified, revert, remove, True, True),
3159 (added, revert, remove, True, False),
3162 (added, revert, remove, True, False),
3160 (removed, undelete, None, False, False),
3163 (removed, undelete, None, False, False),
3161 (deleted, revert, remove, False, False),
3164 (deleted, revert, remove, False, False),
3162 )
3165 )
3163
3166
3164 for abs, (rel, exact) in sorted(names.items()):
3167 for abs, (rel, exact) in sorted(names.items()):
3165 mfentry = mf.get(abs)
3168 mfentry = mf.get(abs)
3166 target = repo.wjoin(abs)
3169 target = repo.wjoin(abs)
3167 def handle(xlist, dobackup):
3170 def handle(xlist, dobackup):
3168 xlist[0].append(abs)
3171 xlist[0].append(abs)
3169 if (dobackup and not opts.get('no_backup') and
3172 if (dobackup and not opts.get('no_backup') and
3170 os.path.lexists(target)):
3173 os.path.lexists(target)):
3171 bakname = "%s.orig" % rel
3174 bakname = "%s.orig" % rel
3172 ui.note(_('saving current version of %s as %s\n') %
3175 ui.note(_('saving current version of %s as %s\n') %
3173 (rel, bakname))
3176 (rel, bakname))
3174 if not opts.get('dry_run'):
3177 if not opts.get('dry_run'):
3175 util.rename(target, bakname)
3178 util.rename(target, bakname)
3176 if ui.verbose or not exact:
3179 if ui.verbose or not exact:
3177 msg = xlist[1]
3180 msg = xlist[1]
3178 if not isinstance(msg, basestring):
3181 if not isinstance(msg, basestring):
3179 msg = msg(abs)
3182 msg = msg(abs)
3180 ui.status(msg % rel)
3183 ui.status(msg % rel)
3181 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3184 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3182 if abs not in table:
3185 if abs not in table:
3183 continue
3186 continue
3184 # file has changed in dirstate
3187 # file has changed in dirstate
3185 if mfentry:
3188 if mfentry:
3186 handle(hitlist, backuphit)
3189 handle(hitlist, backuphit)
3187 elif misslist is not None:
3190 elif misslist is not None:
3188 handle(misslist, backupmiss)
3191 handle(misslist, backupmiss)
3189 break
3192 break
3190 else:
3193 else:
3191 if abs not in repo.dirstate:
3194 if abs not in repo.dirstate:
3192 if mfentry:
3195 if mfentry:
3193 handle(add, True)
3196 handle(add, True)
3194 elif exact:
3197 elif exact:
3195 ui.warn(_('file not managed: %s\n') % rel)
3198 ui.warn(_('file not managed: %s\n') % rel)
3196 continue
3199 continue
3197 # file has not changed in dirstate
3200 # file has not changed in dirstate
3198 if node == parent:
3201 if node == parent:
3199 if exact:
3202 if exact:
3200 ui.warn(_('no changes needed to %s\n') % rel)
3203 ui.warn(_('no changes needed to %s\n') % rel)
3201 continue
3204 continue
3202 if pmf is None:
3205 if pmf is None:
3203 # only need parent manifest in this unlikely case,
3206 # only need parent manifest in this unlikely case,
3204 # so do not read by default
3207 # so do not read by default
3205 pmf = repo[parent].manifest()
3208 pmf = repo[parent].manifest()
3206 if abs in pmf:
3209 if abs in pmf:
3207 if mfentry:
3210 if mfentry:
3208 # if version of file is same in parent and target
3211 # if version of file is same in parent and target
3209 # manifests, do nothing
3212 # manifests, do nothing
3210 if (pmf[abs] != mfentry or
3213 if (pmf[abs] != mfentry or
3211 pmf.flags(abs) != mf.flags(abs)):
3214 pmf.flags(abs) != mf.flags(abs)):
3212 handle(revert, False)
3215 handle(revert, False)
3213 else:
3216 else:
3214 handle(remove, False)
3217 handle(remove, False)
3215
3218
3216 if not opts.get('dry_run'):
3219 if not opts.get('dry_run'):
3217 def checkout(f):
3220 def checkout(f):
3218 fc = ctx[f]
3221 fc = ctx[f]
3219 repo.wwrite(f, fc.data(), fc.flags())
3222 repo.wwrite(f, fc.data(), fc.flags())
3220
3223
3221 audit_path = util.path_auditor(repo.root)
3224 audit_path = util.path_auditor(repo.root)
3222 for f in remove[0]:
3225 for f in remove[0]:
3223 if repo.dirstate[f] == 'a':
3226 if repo.dirstate[f] == 'a':
3224 repo.dirstate.forget(f)
3227 repo.dirstate.forget(f)
3225 continue
3228 continue
3226 audit_path(f)
3229 audit_path(f)
3227 try:
3230 try:
3228 util.unlink(repo.wjoin(f))
3231 util.unlink(repo.wjoin(f))
3229 except OSError:
3232 except OSError:
3230 pass
3233 pass
3231 repo.dirstate.remove(f)
3234 repo.dirstate.remove(f)
3232
3235
3233 normal = None
3236 normal = None
3234 if node == parent:
3237 if node == parent:
3235 # We're reverting to our parent. If possible, we'd like status
3238 # We're reverting to our parent. If possible, we'd like status
3236 # to report the file as clean. We have to use normallookup for
3239 # to report the file as clean. We have to use normallookup for
3237 # merges to avoid losing information about merged/dirty files.
3240 # merges to avoid losing information about merged/dirty files.
3238 if p2 != nullid:
3241 if p2 != nullid:
3239 normal = repo.dirstate.normallookup
3242 normal = repo.dirstate.normallookup
3240 else:
3243 else:
3241 normal = repo.dirstate.normal
3244 normal = repo.dirstate.normal
3242 for f in revert[0]:
3245 for f in revert[0]:
3243 checkout(f)
3246 checkout(f)
3244 if normal:
3247 if normal:
3245 normal(f)
3248 normal(f)
3246
3249
3247 for f in add[0]:
3250 for f in add[0]:
3248 checkout(f)
3251 checkout(f)
3249 repo.dirstate.add(f)
3252 repo.dirstate.add(f)
3250
3253
3251 normal = repo.dirstate.normallookup
3254 normal = repo.dirstate.normallookup
3252 if node == parent and p2 == nullid:
3255 if node == parent and p2 == nullid:
3253 normal = repo.dirstate.normal
3256 normal = repo.dirstate.normal
3254 for f in undelete[0]:
3257 for f in undelete[0]:
3255 checkout(f)
3258 checkout(f)
3256 normal(f)
3259 normal(f)
3257
3260
3258 finally:
3261 finally:
3259 wlock.release()
3262 wlock.release()
3260
3263
3261 def rollback(ui, repo, **opts):
3264 def rollback(ui, repo, **opts):
3262 """roll back the last transaction (dangerous)
3265 """roll back the last transaction (dangerous)
3263
3266
3264 This command should be used with care. There is only one level of
3267 This command should be used with care. There is only one level of
3265 rollback, and there is no way to undo a rollback. It will also
3268 rollback, and there is no way to undo a rollback. It will also
3266 restore the dirstate at the time of the last transaction, losing
3269 restore the dirstate at the time of the last transaction, losing
3267 any dirstate changes since that time. This command does not alter
3270 any dirstate changes since that time. This command does not alter
3268 the working directory.
3271 the working directory.
3269
3272
3270 Transactions are used to encapsulate the effects of all commands
3273 Transactions are used to encapsulate the effects of all commands
3271 that create new changesets or propagate existing changesets into a
3274 that create new changesets or propagate existing changesets into a
3272 repository. For example, the following commands are transactional,
3275 repository. For example, the following commands are transactional,
3273 and their effects can be rolled back:
3276 and their effects can be rolled back:
3274
3277
3275 - commit
3278 - commit
3276 - import
3279 - import
3277 - pull
3280 - pull
3278 - push (with this repository as the destination)
3281 - push (with this repository as the destination)
3279 - unbundle
3282 - unbundle
3280
3283
3281 This command is not intended for use on public repositories. Once
3284 This command is not intended for use on public repositories. Once
3282 changes are visible for pull by other users, rolling a transaction
3285 changes are visible for pull by other users, rolling a transaction
3283 back locally is ineffective (someone else may already have pulled
3286 back locally is ineffective (someone else may already have pulled
3284 the changes). Furthermore, a race is possible with readers of the
3287 the changes). Furthermore, a race is possible with readers of the
3285 repository; for example an in-progress pull from the repository
3288 repository; for example an in-progress pull from the repository
3286 may fail if a rollback is performed.
3289 may fail if a rollback is performed.
3287
3290
3288 Returns 0 on success, 1 if no rollback data is available.
3291 Returns 0 on success, 1 if no rollback data is available.
3289 """
3292 """
3290 return repo.rollback(opts.get('dry_run'))
3293 return repo.rollback(opts.get('dry_run'))
3291
3294
3292 def root(ui, repo):
3295 def root(ui, repo):
3293 """print the root (top) of the current working directory
3296 """print the root (top) of the current working directory
3294
3297
3295 Print the root directory of the current repository.
3298 Print the root directory of the current repository.
3296
3299
3297 Returns 0 on success.
3300 Returns 0 on success.
3298 """
3301 """
3299 ui.write(repo.root + "\n")
3302 ui.write(repo.root + "\n")
3300
3303
3301 def serve(ui, repo, **opts):
3304 def serve(ui, repo, **opts):
3302 """start stand-alone webserver
3305 """start stand-alone webserver
3303
3306
3304 Start a local HTTP repository browser and pull server. You can use
3307 Start a local HTTP repository browser and pull server. You can use
3305 this for ad-hoc sharing and browing of repositories. It is
3308 this for ad-hoc sharing and browing of repositories. It is
3306 recommended to use a real web server to serve a repository for
3309 recommended to use a real web server to serve a repository for
3307 longer periods of time.
3310 longer periods of time.
3308
3311
3309 Please note that the server does not implement access control.
3312 Please note that the server does not implement access control.
3310 This means that, by default, anybody can read from the server and
3313 This means that, by default, anybody can read from the server and
3311 nobody can write to it by default. Set the ``web.allow_push``
3314 nobody can write to it by default. Set the ``web.allow_push``
3312 option to ``*`` to allow everybody to push to the server. You
3315 option to ``*`` to allow everybody to push to the server. You
3313 should use a real web server if you need to authenticate users.
3316 should use a real web server if you need to authenticate users.
3314
3317
3315 By default, the server logs accesses to stdout and errors to
3318 By default, the server logs accesses to stdout and errors to
3316 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3319 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3317 files.
3320 files.
3318
3321
3319 To have the server choose a free port number to listen on, specify
3322 To have the server choose a free port number to listen on, specify
3320 a port number of 0; in this case, the server will print the port
3323 a port number of 0; in this case, the server will print the port
3321 number it uses.
3324 number it uses.
3322
3325
3323 Returns 0 on success.
3326 Returns 0 on success.
3324 """
3327 """
3325
3328
3326 if opts["stdio"]:
3329 if opts["stdio"]:
3327 if repo is None:
3330 if repo is None:
3328 raise error.RepoError(_("There is no Mercurial repository here"
3331 raise error.RepoError(_("There is no Mercurial repository here"
3329 " (.hg not found)"))
3332 " (.hg not found)"))
3330 s = sshserver.sshserver(ui, repo)
3333 s = sshserver.sshserver(ui, repo)
3331 s.serve_forever()
3334 s.serve_forever()
3332
3335
3333 # this way we can check if something was given in the command-line
3336 # this way we can check if something was given in the command-line
3334 if opts.get('port'):
3337 if opts.get('port'):
3335 opts['port'] = util.getport(opts.get('port'))
3338 opts['port'] = util.getport(opts.get('port'))
3336
3339
3337 baseui = repo and repo.baseui or ui
3340 baseui = repo and repo.baseui or ui
3338 optlist = ("name templates style address port prefix ipv6"
3341 optlist = ("name templates style address port prefix ipv6"
3339 " accesslog errorlog certificate encoding")
3342 " accesslog errorlog certificate encoding")
3340 for o in optlist.split():
3343 for o in optlist.split():
3341 val = opts.get(o, '')
3344 val = opts.get(o, '')
3342 if val in (None, ''): # should check against default options instead
3345 if val in (None, ''): # should check against default options instead
3343 continue
3346 continue
3344 baseui.setconfig("web", o, val)
3347 baseui.setconfig("web", o, val)
3345 if repo and repo.ui != baseui:
3348 if repo and repo.ui != baseui:
3346 repo.ui.setconfig("web", o, val)
3349 repo.ui.setconfig("web", o, val)
3347
3350
3348 o = opts.get('web_conf') or opts.get('webdir_conf')
3351 o = opts.get('web_conf') or opts.get('webdir_conf')
3349 if not o:
3352 if not o:
3350 if not repo:
3353 if not repo:
3351 raise error.RepoError(_("There is no Mercurial repository"
3354 raise error.RepoError(_("There is no Mercurial repository"
3352 " here (.hg not found)"))
3355 " here (.hg not found)"))
3353 o = repo.root
3356 o = repo.root
3354
3357
3355 app = hgweb.hgweb(o, baseui=ui)
3358 app = hgweb.hgweb(o, baseui=ui)
3356
3359
3357 class service(object):
3360 class service(object):
3358 def init(self):
3361 def init(self):
3359 util.set_signal_handler()
3362 util.set_signal_handler()
3360 self.httpd = hgweb.server.create_server(ui, app)
3363 self.httpd = hgweb.server.create_server(ui, app)
3361
3364
3362 if opts['port'] and not ui.verbose:
3365 if opts['port'] and not ui.verbose:
3363 return
3366 return
3364
3367
3365 if self.httpd.prefix:
3368 if self.httpd.prefix:
3366 prefix = self.httpd.prefix.strip('/') + '/'
3369 prefix = self.httpd.prefix.strip('/') + '/'
3367 else:
3370 else:
3368 prefix = ''
3371 prefix = ''
3369
3372
3370 port = ':%d' % self.httpd.port
3373 port = ':%d' % self.httpd.port
3371 if port == ':80':
3374 if port == ':80':
3372 port = ''
3375 port = ''
3373
3376
3374 bindaddr = self.httpd.addr
3377 bindaddr = self.httpd.addr
3375 if bindaddr == '0.0.0.0':
3378 if bindaddr == '0.0.0.0':
3376 bindaddr = '*'
3379 bindaddr = '*'
3377 elif ':' in bindaddr: # IPv6
3380 elif ':' in bindaddr: # IPv6
3378 bindaddr = '[%s]' % bindaddr
3381 bindaddr = '[%s]' % bindaddr
3379
3382
3380 fqaddr = self.httpd.fqaddr
3383 fqaddr = self.httpd.fqaddr
3381 if ':' in fqaddr:
3384 if ':' in fqaddr:
3382 fqaddr = '[%s]' % fqaddr
3385 fqaddr = '[%s]' % fqaddr
3383 if opts['port']:
3386 if opts['port']:
3384 write = ui.status
3387 write = ui.status
3385 else:
3388 else:
3386 write = ui.write
3389 write = ui.write
3387 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3390 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3388 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3391 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3389
3392
3390 def run(self):
3393 def run(self):
3391 self.httpd.serve_forever()
3394 self.httpd.serve_forever()
3392
3395
3393 service = service()
3396 service = service()
3394
3397
3395 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3398 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3396
3399
3397 def status(ui, repo, *pats, **opts):
3400 def status(ui, repo, *pats, **opts):
3398 """show changed files in the working directory
3401 """show changed files in the working directory
3399
3402
3400 Show status of files in the repository. If names are given, only
3403 Show status of files in the repository. If names are given, only
3401 files that match are shown. Files that are clean or ignored or
3404 files that match are shown. Files that are clean or ignored or
3402 the source of a copy/move operation, are not listed unless
3405 the source of a copy/move operation, are not listed unless
3403 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3406 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3404 Unless options described with "show only ..." are given, the
3407 Unless options described with "show only ..." are given, the
3405 options -mardu are used.
3408 options -mardu are used.
3406
3409
3407 Option -q/--quiet hides untracked (unknown and ignored) files
3410 Option -q/--quiet hides untracked (unknown and ignored) files
3408 unless explicitly requested with -u/--unknown or -i/--ignored.
3411 unless explicitly requested with -u/--unknown or -i/--ignored.
3409
3412
3410 NOTE: status may appear to disagree with diff if permissions have
3413 NOTE: status may appear to disagree with diff if permissions have
3411 changed or a merge has occurred. The standard diff format does not
3414 changed or a merge has occurred. The standard diff format does not
3412 report permission changes and diff only reports changes relative
3415 report permission changes and diff only reports changes relative
3413 to one merge parent.
3416 to one merge parent.
3414
3417
3415 If one revision is given, it is used as the base revision.
3418 If one revision is given, it is used as the base revision.
3416 If two revisions are given, the differences between them are
3419 If two revisions are given, the differences between them are
3417 shown. The --change option can also be used as a shortcut to list
3420 shown. The --change option can also be used as a shortcut to list
3418 the changed files of a revision from its first parent.
3421 the changed files of a revision from its first parent.
3419
3422
3420 The codes used to show the status of files are::
3423 The codes used to show the status of files are::
3421
3424
3422 M = modified
3425 M = modified
3423 A = added
3426 A = added
3424 R = removed
3427 R = removed
3425 C = clean
3428 C = clean
3426 ! = missing (deleted by non-hg command, but still tracked)
3429 ! = missing (deleted by non-hg command, but still tracked)
3427 ? = not tracked
3430 ? = not tracked
3428 I = ignored
3431 I = ignored
3429 = origin of the previous file listed as A (added)
3432 = origin of the previous file listed as A (added)
3430
3433
3431 Returns 0 on success.
3434 Returns 0 on success.
3432 """
3435 """
3433
3436
3434 revs = opts.get('rev')
3437 revs = opts.get('rev')
3435 change = opts.get('change')
3438 change = opts.get('change')
3436
3439
3437 if revs and change:
3440 if revs and change:
3438 msg = _('cannot specify --rev and --change at the same time')
3441 msg = _('cannot specify --rev and --change at the same time')
3439 raise util.Abort(msg)
3442 raise util.Abort(msg)
3440 elif change:
3443 elif change:
3441 node2 = repo.lookup(change)
3444 node2 = repo.lookup(change)
3442 node1 = repo[node2].parents()[0].node()
3445 node1 = repo[node2].parents()[0].node()
3443 else:
3446 else:
3444 node1, node2 = cmdutil.revpair(repo, revs)
3447 node1, node2 = cmdutil.revpair(repo, revs)
3445
3448
3446 cwd = (pats and repo.getcwd()) or ''
3449 cwd = (pats and repo.getcwd()) or ''
3447 end = opts.get('print0') and '\0' or '\n'
3450 end = opts.get('print0') and '\0' or '\n'
3448 copy = {}
3451 copy = {}
3449 states = 'modified added removed deleted unknown ignored clean'.split()
3452 states = 'modified added removed deleted unknown ignored clean'.split()
3450 show = [k for k in states if opts.get(k)]
3453 show = [k for k in states if opts.get(k)]
3451 if opts.get('all'):
3454 if opts.get('all'):
3452 show += ui.quiet and (states[:4] + ['clean']) or states
3455 show += ui.quiet and (states[:4] + ['clean']) or states
3453 if not show:
3456 if not show:
3454 show = ui.quiet and states[:4] or states[:5]
3457 show = ui.quiet and states[:4] or states[:5]
3455
3458
3456 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3459 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3457 'ignored' in show, 'clean' in show, 'unknown' in show)
3460 'ignored' in show, 'clean' in show, 'unknown' in show)
3458 changestates = zip(states, 'MAR!?IC', stat)
3461 changestates = zip(states, 'MAR!?IC', stat)
3459
3462
3460 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3463 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3461 ctxn = repo[nullid]
3464 ctxn = repo[nullid]
3462 ctx1 = repo[node1]
3465 ctx1 = repo[node1]
3463 ctx2 = repo[node2]
3466 ctx2 = repo[node2]
3464 added = stat[1]
3467 added = stat[1]
3465 if node2 is None:
3468 if node2 is None:
3466 added = stat[0] + stat[1] # merged?
3469 added = stat[0] + stat[1] # merged?
3467
3470
3468 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3471 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3469 if k in added:
3472 if k in added:
3470 copy[k] = v
3473 copy[k] = v
3471 elif v in added:
3474 elif v in added:
3472 copy[v] = k
3475 copy[v] = k
3473
3476
3474 for state, char, files in changestates:
3477 for state, char, files in changestates:
3475 if state in show:
3478 if state in show:
3476 format = "%s %%s%s" % (char, end)
3479 format = "%s %%s%s" % (char, end)
3477 if opts.get('no_status'):
3480 if opts.get('no_status'):
3478 format = "%%s%s" % end
3481 format = "%%s%s" % end
3479
3482
3480 for f in files:
3483 for f in files:
3481 ui.write(format % repo.pathto(f, cwd),
3484 ui.write(format % repo.pathto(f, cwd),
3482 label='status.' + state)
3485 label='status.' + state)
3483 if f in copy:
3486 if f in copy:
3484 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3487 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3485 label='status.copied')
3488 label='status.copied')
3486
3489
3487 def summary(ui, repo, **opts):
3490 def summary(ui, repo, **opts):
3488 """summarize working directory state
3491 """summarize working directory state
3489
3492
3490 This generates a brief summary of the working directory state,
3493 This generates a brief summary of the working directory state,
3491 including parents, branch, commit status, and available updates.
3494 including parents, branch, commit status, and available updates.
3492
3495
3493 With the --remote option, this will check the default paths for
3496 With the --remote option, this will check the default paths for
3494 incoming and outgoing changes. This can be time-consuming.
3497 incoming and outgoing changes. This can be time-consuming.
3495
3498
3496 Returns 0 on success.
3499 Returns 0 on success.
3497 """
3500 """
3498
3501
3499 ctx = repo[None]
3502 ctx = repo[None]
3500 parents = ctx.parents()
3503 parents = ctx.parents()
3501 pnode = parents[0].node()
3504 pnode = parents[0].node()
3502
3505
3503 for p in parents:
3506 for p in parents:
3504 # label with log.changeset (instead of log.parent) since this
3507 # label with log.changeset (instead of log.parent) since this
3505 # shows a working directory parent *changeset*:
3508 # shows a working directory parent *changeset*:
3506 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3509 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3507 label='log.changeset')
3510 label='log.changeset')
3508 ui.write(' '.join(p.tags()), label='log.tag')
3511 ui.write(' '.join(p.tags()), label='log.tag')
3509 if p.rev() == -1:
3512 if p.rev() == -1:
3510 if not len(repo):
3513 if not len(repo):
3511 ui.write(_(' (empty repository)'))
3514 ui.write(_(' (empty repository)'))
3512 else:
3515 else:
3513 ui.write(_(' (no revision checked out)'))
3516 ui.write(_(' (no revision checked out)'))
3514 ui.write('\n')
3517 ui.write('\n')
3515 if p.description():
3518 if p.description():
3516 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3519 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3517 label='log.summary')
3520 label='log.summary')
3518
3521
3519 branch = ctx.branch()
3522 branch = ctx.branch()
3520 bheads = repo.branchheads(branch)
3523 bheads = repo.branchheads(branch)
3521 m = _('branch: %s\n') % branch
3524 m = _('branch: %s\n') % branch
3522 if branch != 'default':
3525 if branch != 'default':
3523 ui.write(m, label='log.branch')
3526 ui.write(m, label='log.branch')
3524 else:
3527 else:
3525 ui.status(m, label='log.branch')
3528 ui.status(m, label='log.branch')
3526
3529
3527 st = list(repo.status(unknown=True))[:6]
3530 st = list(repo.status(unknown=True))[:6]
3528
3531
3529 c = repo.dirstate.copies()
3532 c = repo.dirstate.copies()
3530 copied, renamed = [], []
3533 copied, renamed = [], []
3531 for d, s in c.iteritems():
3534 for d, s in c.iteritems():
3532 if s in st[2]:
3535 if s in st[2]:
3533 st[2].remove(s)
3536 st[2].remove(s)
3534 renamed.append(d)
3537 renamed.append(d)
3535 else:
3538 else:
3536 copied.append(d)
3539 copied.append(d)
3537 if d in st[1]:
3540 if d in st[1]:
3538 st[1].remove(d)
3541 st[1].remove(d)
3539 st.insert(3, renamed)
3542 st.insert(3, renamed)
3540 st.insert(4, copied)
3543 st.insert(4, copied)
3541
3544
3542 ms = mergemod.mergestate(repo)
3545 ms = mergemod.mergestate(repo)
3543 st.append([f for f in ms if ms[f] == 'u'])
3546 st.append([f for f in ms if ms[f] == 'u'])
3544
3547
3545 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3548 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3546 st.append(subs)
3549 st.append(subs)
3547
3550
3548 labels = [ui.label(_('%d modified'), 'status.modified'),
3551 labels = [ui.label(_('%d modified'), 'status.modified'),
3549 ui.label(_('%d added'), 'status.added'),
3552 ui.label(_('%d added'), 'status.added'),
3550 ui.label(_('%d removed'), 'status.removed'),
3553 ui.label(_('%d removed'), 'status.removed'),
3551 ui.label(_('%d renamed'), 'status.copied'),
3554 ui.label(_('%d renamed'), 'status.copied'),
3552 ui.label(_('%d copied'), 'status.copied'),
3555 ui.label(_('%d copied'), 'status.copied'),
3553 ui.label(_('%d deleted'), 'status.deleted'),
3556 ui.label(_('%d deleted'), 'status.deleted'),
3554 ui.label(_('%d unknown'), 'status.unknown'),
3557 ui.label(_('%d unknown'), 'status.unknown'),
3555 ui.label(_('%d ignored'), 'status.ignored'),
3558 ui.label(_('%d ignored'), 'status.ignored'),
3556 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3559 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3557 ui.label(_('%d subrepos'), 'status.modified')]
3560 ui.label(_('%d subrepos'), 'status.modified')]
3558 t = []
3561 t = []
3559 for s, l in zip(st, labels):
3562 for s, l in zip(st, labels):
3560 if s:
3563 if s:
3561 t.append(l % len(s))
3564 t.append(l % len(s))
3562
3565
3563 t = ', '.join(t)
3566 t = ', '.join(t)
3564 cleanworkdir = False
3567 cleanworkdir = False
3565
3568
3566 if len(parents) > 1:
3569 if len(parents) > 1:
3567 t += _(' (merge)')
3570 t += _(' (merge)')
3568 elif branch != parents[0].branch():
3571 elif branch != parents[0].branch():
3569 t += _(' (new branch)')
3572 t += _(' (new branch)')
3570 elif (parents[0].extra().get('close') and
3573 elif (parents[0].extra().get('close') and
3571 pnode in repo.branchheads(branch, closed=True)):
3574 pnode in repo.branchheads(branch, closed=True)):
3572 t += _(' (head closed)')
3575 t += _(' (head closed)')
3573 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3576 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3574 t += _(' (clean)')
3577 t += _(' (clean)')
3575 cleanworkdir = True
3578 cleanworkdir = True
3576 elif pnode not in bheads:
3579 elif pnode not in bheads:
3577 t += _(' (new branch head)')
3580 t += _(' (new branch head)')
3578
3581
3579 if cleanworkdir:
3582 if cleanworkdir:
3580 ui.status(_('commit: %s\n') % t.strip())
3583 ui.status(_('commit: %s\n') % t.strip())
3581 else:
3584 else:
3582 ui.write(_('commit: %s\n') % t.strip())
3585 ui.write(_('commit: %s\n') % t.strip())
3583
3586
3584 # all ancestors of branch heads - all ancestors of parent = new csets
3587 # all ancestors of branch heads - all ancestors of parent = new csets
3585 new = [0] * len(repo)
3588 new = [0] * len(repo)
3586 cl = repo.changelog
3589 cl = repo.changelog
3587 for a in [cl.rev(n) for n in bheads]:
3590 for a in [cl.rev(n) for n in bheads]:
3588 new[a] = 1
3591 new[a] = 1
3589 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3592 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3590 new[a] = 1
3593 new[a] = 1
3591 for a in [p.rev() for p in parents]:
3594 for a in [p.rev() for p in parents]:
3592 if a >= 0:
3595 if a >= 0:
3593 new[a] = 0
3596 new[a] = 0
3594 for a in cl.ancestors(*[p.rev() for p in parents]):
3597 for a in cl.ancestors(*[p.rev() for p in parents]):
3595 new[a] = 0
3598 new[a] = 0
3596 new = sum(new)
3599 new = sum(new)
3597
3600
3598 if new == 0:
3601 if new == 0:
3599 ui.status(_('update: (current)\n'))
3602 ui.status(_('update: (current)\n'))
3600 elif pnode not in bheads:
3603 elif pnode not in bheads:
3601 ui.write(_('update: %d new changesets (update)\n') % new)
3604 ui.write(_('update: %d new changesets (update)\n') % new)
3602 else:
3605 else:
3603 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3606 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3604 (new, len(bheads)))
3607 (new, len(bheads)))
3605
3608
3606 if opts.get('remote'):
3609 if opts.get('remote'):
3607 t = []
3610 t = []
3608 source, branches = hg.parseurl(ui.expandpath('default'))
3611 source, branches = hg.parseurl(ui.expandpath('default'))
3609 other = hg.repository(hg.remoteui(repo, {}), source)
3612 other = hg.repository(hg.remoteui(repo, {}), source)
3610 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3613 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3611 ui.debug('comparing with %s\n' % url.hidepassword(source))
3614 ui.debug('comparing with %s\n' % url.hidepassword(source))
3612 repo.ui.pushbuffer()
3615 repo.ui.pushbuffer()
3613 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3616 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3614 repo.ui.popbuffer()
3617 repo.ui.popbuffer()
3615 if incoming:
3618 if incoming:
3616 t.append(_('1 or more incoming'))
3619 t.append(_('1 or more incoming'))
3617
3620
3618 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3621 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3619 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3622 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3620 other = hg.repository(hg.remoteui(repo, {}), dest)
3623 other = hg.repository(hg.remoteui(repo, {}), dest)
3621 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3624 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3622 repo.ui.pushbuffer()
3625 repo.ui.pushbuffer()
3623 o = discovery.findoutgoing(repo, other)
3626 o = discovery.findoutgoing(repo, other)
3624 repo.ui.popbuffer()
3627 repo.ui.popbuffer()
3625 o = repo.changelog.nodesbetween(o, None)[0]
3628 o = repo.changelog.nodesbetween(o, None)[0]
3626 if o:
3629 if o:
3627 t.append(_('%d outgoing') % len(o))
3630 t.append(_('%d outgoing') % len(o))
3628
3631
3629 if t:
3632 if t:
3630 ui.write(_('remote: %s\n') % (', '.join(t)))
3633 ui.write(_('remote: %s\n') % (', '.join(t)))
3631 else:
3634 else:
3632 ui.status(_('remote: (synced)\n'))
3635 ui.status(_('remote: (synced)\n'))
3633
3636
3634 def tag(ui, repo, name1, *names, **opts):
3637 def tag(ui, repo, name1, *names, **opts):
3635 """add one or more tags for the current or given revision
3638 """add one or more tags for the current or given revision
3636
3639
3637 Name a particular revision using <name>.
3640 Name a particular revision using <name>.
3638
3641
3639 Tags are used to name particular revisions of the repository and are
3642 Tags are used to name particular revisions of the repository and are
3640 very useful to compare different revisions, to go back to significant
3643 very useful to compare different revisions, to go back to significant
3641 earlier versions or to mark branch points as releases, etc.
3644 earlier versions or to mark branch points as releases, etc.
3642
3645
3643 If no revision is given, the parent of the working directory is
3646 If no revision is given, the parent of the working directory is
3644 used, or tip if no revision is checked out.
3647 used, or tip if no revision is checked out.
3645
3648
3646 To facilitate version control, distribution, and merging of tags,
3649 To facilitate version control, distribution, and merging of tags,
3647 they are stored as a file named ".hgtags" which is managed
3650 they are stored as a file named ".hgtags" which is managed
3648 similarly to other project files and can be hand-edited if
3651 similarly to other project files and can be hand-edited if
3649 necessary. The file '.hg/localtags' is used for local tags (not
3652 necessary. The file '.hg/localtags' is used for local tags (not
3650 shared among repositories).
3653 shared among repositories).
3651
3654
3652 See :hg:`help dates` for a list of formats valid for -d/--date.
3655 See :hg:`help dates` for a list of formats valid for -d/--date.
3653
3656
3654 Since tag names have priority over branch names during revision
3657 Since tag names have priority over branch names during revision
3655 lookup, using an existing branch name as a tag name is discouraged.
3658 lookup, using an existing branch name as a tag name is discouraged.
3656
3659
3657 Returns 0 on success.
3660 Returns 0 on success.
3658 """
3661 """
3659
3662
3660 rev_ = "."
3663 rev_ = "."
3661 names = [t.strip() for t in (name1,) + names]
3664 names = [t.strip() for t in (name1,) + names]
3662 if len(names) != len(set(names)):
3665 if len(names) != len(set(names)):
3663 raise util.Abort(_('tag names must be unique'))
3666 raise util.Abort(_('tag names must be unique'))
3664 for n in names:
3667 for n in names:
3665 if n in ['tip', '.', 'null']:
3668 if n in ['tip', '.', 'null']:
3666 raise util.Abort(_('the name \'%s\' is reserved') % n)
3669 raise util.Abort(_('the name \'%s\' is reserved') % n)
3667 if not n:
3670 if not n:
3668 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3671 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3669 if opts.get('rev') and opts.get('remove'):
3672 if opts.get('rev') and opts.get('remove'):
3670 raise util.Abort(_("--rev and --remove are incompatible"))
3673 raise util.Abort(_("--rev and --remove are incompatible"))
3671 if opts.get('rev'):
3674 if opts.get('rev'):
3672 rev_ = opts['rev']
3675 rev_ = opts['rev']
3673 message = opts.get('message')
3676 message = opts.get('message')
3674 if opts.get('remove'):
3677 if opts.get('remove'):
3675 expectedtype = opts.get('local') and 'local' or 'global'
3678 expectedtype = opts.get('local') and 'local' or 'global'
3676 for n in names:
3679 for n in names:
3677 if not repo.tagtype(n):
3680 if not repo.tagtype(n):
3678 raise util.Abort(_('tag \'%s\' does not exist') % n)
3681 raise util.Abort(_('tag \'%s\' does not exist') % n)
3679 if repo.tagtype(n) != expectedtype:
3682 if repo.tagtype(n) != expectedtype:
3680 if expectedtype == 'global':
3683 if expectedtype == 'global':
3681 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3684 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3682 else:
3685 else:
3683 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3686 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3684 rev_ = nullid
3687 rev_ = nullid
3685 if not message:
3688 if not message:
3686 # we don't translate commit messages
3689 # we don't translate commit messages
3687 message = 'Removed tag %s' % ', '.join(names)
3690 message = 'Removed tag %s' % ', '.join(names)
3688 elif not opts.get('force'):
3691 elif not opts.get('force'):
3689 for n in names:
3692 for n in names:
3690 if n in repo.tags():
3693 if n in repo.tags():
3691 raise util.Abort(_('tag \'%s\' already exists '
3694 raise util.Abort(_('tag \'%s\' already exists '
3692 '(use -f to force)') % n)
3695 '(use -f to force)') % n)
3693 if not rev_ and repo.dirstate.parents()[1] != nullid:
3696 if not rev_ and repo.dirstate.parents()[1] != nullid:
3694 raise util.Abort(_('uncommitted merge - please provide a '
3697 raise util.Abort(_('uncommitted merge - please provide a '
3695 'specific revision'))
3698 'specific revision'))
3696 r = repo[rev_].node()
3699 r = repo[rev_].node()
3697
3700
3698 if not message:
3701 if not message:
3699 # we don't translate commit messages
3702 # we don't translate commit messages
3700 message = ('Added tag %s for changeset %s' %
3703 message = ('Added tag %s for changeset %s' %
3701 (', '.join(names), short(r)))
3704 (', '.join(names), short(r)))
3702
3705
3703 date = opts.get('date')
3706 date = opts.get('date')
3704 if date:
3707 if date:
3705 date = util.parsedate(date)
3708 date = util.parsedate(date)
3706
3709
3707 if opts.get('edit'):
3710 if opts.get('edit'):
3708 message = ui.edit(message, ui.username())
3711 message = ui.edit(message, ui.username())
3709
3712
3710 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3713 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3711
3714
3712 def tags(ui, repo):
3715 def tags(ui, repo):
3713 """list repository tags
3716 """list repository tags
3714
3717
3715 This lists both regular and local tags. When the -v/--verbose
3718 This lists both regular and local tags. When the -v/--verbose
3716 switch is used, a third column "local" is printed for local tags.
3719 switch is used, a third column "local" is printed for local tags.
3717
3720
3718 Returns 0 on success.
3721 Returns 0 on success.
3719 """
3722 """
3720
3723
3721 hexfunc = ui.debugflag and hex or short
3724 hexfunc = ui.debugflag and hex or short
3722 tagtype = ""
3725 tagtype = ""
3723
3726
3724 for t, n in reversed(repo.tagslist()):
3727 for t, n in reversed(repo.tagslist()):
3725 if ui.quiet:
3728 if ui.quiet:
3726 ui.write("%s\n" % t)
3729 ui.write("%s\n" % t)
3727 continue
3730 continue
3728
3731
3729 try:
3732 try:
3730 hn = hexfunc(n)
3733 hn = hexfunc(n)
3731 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3734 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3732 except error.LookupError:
3735 except error.LookupError:
3733 r = " ?:%s" % hn
3736 r = " ?:%s" % hn
3734 else:
3737 else:
3735 spaces = " " * (30 - encoding.colwidth(t))
3738 spaces = " " * (30 - encoding.colwidth(t))
3736 if ui.verbose:
3739 if ui.verbose:
3737 if repo.tagtype(t) == 'local':
3740 if repo.tagtype(t) == 'local':
3738 tagtype = " local"
3741 tagtype = " local"
3739 else:
3742 else:
3740 tagtype = ""
3743 tagtype = ""
3741 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3744 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3742
3745
3743 def tip(ui, repo, **opts):
3746 def tip(ui, repo, **opts):
3744 """show the tip revision
3747 """show the tip revision
3745
3748
3746 The tip revision (usually just called the tip) is the changeset
3749 The tip revision (usually just called the tip) is the changeset
3747 most recently added to the repository (and therefore the most
3750 most recently added to the repository (and therefore the most
3748 recently changed head).
3751 recently changed head).
3749
3752
3750 If you have just made a commit, that commit will be the tip. If
3753 If you have just made a commit, that commit will be the tip. If
3751 you have just pulled changes from another repository, the tip of
3754 you have just pulled changes from another repository, the tip of
3752 that repository becomes the current tip. The "tip" tag is special
3755 that repository becomes the current tip. The "tip" tag is special
3753 and cannot be renamed or assigned to a different changeset.
3756 and cannot be renamed or assigned to a different changeset.
3754
3757
3755 Returns 0 on success.
3758 Returns 0 on success.
3756 """
3759 """
3757 displayer = cmdutil.show_changeset(ui, repo, opts)
3760 displayer = cmdutil.show_changeset(ui, repo, opts)
3758 displayer.show(repo[len(repo) - 1])
3761 displayer.show(repo[len(repo) - 1])
3759 displayer.close()
3762 displayer.close()
3760
3763
3761 def unbundle(ui, repo, fname1, *fnames, **opts):
3764 def unbundle(ui, repo, fname1, *fnames, **opts):
3762 """apply one or more changegroup files
3765 """apply one or more changegroup files
3763
3766
3764 Apply one or more compressed changegroup files generated by the
3767 Apply one or more compressed changegroup files generated by the
3765 bundle command.
3768 bundle command.
3766
3769
3767 Returns 0 on success, 1 if an update has unresolved files.
3770 Returns 0 on success, 1 if an update has unresolved files.
3768 """
3771 """
3769 fnames = (fname1,) + fnames
3772 fnames = (fname1,) + fnames
3770
3773
3771 lock = repo.lock()
3774 lock = repo.lock()
3772 try:
3775 try:
3773 for fname in fnames:
3776 for fname in fnames:
3774 f = url.open(ui, fname)
3777 f = url.open(ui, fname)
3775 gen = changegroup.readbundle(f, fname)
3778 gen = changegroup.readbundle(f, fname)
3776 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3779 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3777 lock=lock)
3780 lock=lock)
3778 finally:
3781 finally:
3779 lock.release()
3782 lock.release()
3780
3783
3781 return postincoming(ui, repo, modheads, opts.get('update'), None)
3784 return postincoming(ui, repo, modheads, opts.get('update'), None)
3782
3785
3783 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3786 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3784 """update working directory (or switch revisions)
3787 """update working directory (or switch revisions)
3785
3788
3786 Update the repository's working directory to the specified
3789 Update the repository's working directory to the specified
3787 changeset.
3790 changeset.
3788
3791
3789 If no changeset is specified, attempt to update to the tip of the
3792 If no changeset is specified, attempt to update to the tip of the
3790 current branch. If this changeset is a descendant of the working
3793 current branch. If this changeset is a descendant of the working
3791 directory's parent, update to it, otherwise abort.
3794 directory's parent, update to it, otherwise abort.
3792
3795
3793 The following rules apply when the working directory contains
3796 The following rules apply when the working directory contains
3794 uncommitted changes:
3797 uncommitted changes:
3795
3798
3796 1. If neither -c/--check nor -C/--clean is specified, and if
3799 1. If neither -c/--check nor -C/--clean is specified, and if
3797 the requested changeset is an ancestor or descendant of
3800 the requested changeset is an ancestor or descendant of
3798 the working directory's parent, the uncommitted changes
3801 the working directory's parent, the uncommitted changes
3799 are merged into the requested changeset and the merged
3802 are merged into the requested changeset and the merged
3800 result is left uncommitted. If the requested changeset is
3803 result is left uncommitted. If the requested changeset is
3801 not an ancestor or descendant (that is, it is on another
3804 not an ancestor or descendant (that is, it is on another
3802 branch), the update is aborted and the uncommitted changes
3805 branch), the update is aborted and the uncommitted changes
3803 are preserved.
3806 are preserved.
3804
3807
3805 2. With the -c/--check option, the update is aborted and the
3808 2. With the -c/--check option, the update is aborted and the
3806 uncommitted changes are preserved.
3809 uncommitted changes are preserved.
3807
3810
3808 3. With the -C/--clean option, uncommitted changes are discarded and
3811 3. With the -C/--clean option, uncommitted changes are discarded and
3809 the working directory is updated to the requested changeset.
3812 the working directory is updated to the requested changeset.
3810
3813
3811 Use null as the changeset to remove the working directory (like
3814 Use null as the changeset to remove the working directory (like
3812 :hg:`clone -U`).
3815 :hg:`clone -U`).
3813
3816
3814 If you want to update just one file to an older changeset, use :hg:`revert`.
3817 If you want to update just one file to an older changeset, use :hg:`revert`.
3815
3818
3816 See :hg:`help dates` for a list of formats valid for -d/--date.
3819 See :hg:`help dates` for a list of formats valid for -d/--date.
3817
3820
3818 Returns 0 on success, 1 if there are unresolved files.
3821 Returns 0 on success, 1 if there are unresolved files.
3819 """
3822 """
3820 if rev and node:
3823 if rev and node:
3821 raise util.Abort(_("please specify just one revision"))
3824 raise util.Abort(_("please specify just one revision"))
3822
3825
3823 if not rev:
3826 if not rev:
3824 rev = node
3827 rev = node
3825
3828
3826 if check and clean:
3829 if check and clean:
3827 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3830 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3828
3831
3829 if check:
3832 if check:
3830 # we could use dirty() but we can ignore merge and branch trivia
3833 # we could use dirty() but we can ignore merge and branch trivia
3831 c = repo[None]
3834 c = repo[None]
3832 if c.modified() or c.added() or c.removed():
3835 if c.modified() or c.added() or c.removed():
3833 raise util.Abort(_("uncommitted local changes"))
3836 raise util.Abort(_("uncommitted local changes"))
3834
3837
3835 if date:
3838 if date:
3836 if rev:
3839 if rev:
3837 raise util.Abort(_("you can't specify a revision and a date"))
3840 raise util.Abort(_("you can't specify a revision and a date"))
3838 rev = cmdutil.finddate(ui, repo, date)
3841 rev = cmdutil.finddate(ui, repo, date)
3839
3842
3840 if clean or check:
3843 if clean or check:
3841 return hg.clean(repo, rev)
3844 return hg.clean(repo, rev)
3842 else:
3845 else:
3843 return hg.update(repo, rev)
3846 return hg.update(repo, rev)
3844
3847
3845 def verify(ui, repo):
3848 def verify(ui, repo):
3846 """verify the integrity of the repository
3849 """verify the integrity of the repository
3847
3850
3848 Verify the integrity of the current repository.
3851 Verify the integrity of the current repository.
3849
3852
3850 This will perform an extensive check of the repository's
3853 This will perform an extensive check of the repository's
3851 integrity, validating the hashes and checksums of each entry in
3854 integrity, validating the hashes and checksums of each entry in
3852 the changelog, manifest, and tracked files, as well as the
3855 the changelog, manifest, and tracked files, as well as the
3853 integrity of their crosslinks and indices.
3856 integrity of their crosslinks and indices.
3854
3857
3855 Returns 0 on success, 1 if errors are encountered.
3858 Returns 0 on success, 1 if errors are encountered.
3856 """
3859 """
3857 return hg.verify(repo)
3860 return hg.verify(repo)
3858
3861
3859 def version_(ui):
3862 def version_(ui):
3860 """output version and copyright information"""
3863 """output version and copyright information"""
3861 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3864 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3862 % util.version())
3865 % util.version())
3863 ui.status(_(
3866 ui.status(_(
3864 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3867 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3865 "This is free software; see the source for copying conditions. "
3868 "This is free software; see the source for copying conditions. "
3866 "There is NO\nwarranty; "
3869 "There is NO\nwarranty; "
3867 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3870 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3868 ))
3871 ))
3869
3872
3870 # Command options and aliases are listed here, alphabetically
3873 # Command options and aliases are listed here, alphabetically
3871
3874
3872 globalopts = [
3875 globalopts = [
3873 ('R', 'repository', '',
3876 ('R', 'repository', '',
3874 _('repository root directory or name of overlay bundle file'),
3877 _('repository root directory or name of overlay bundle file'),
3875 _('REPO')),
3878 _('REPO')),
3876 ('', 'cwd', '',
3879 ('', 'cwd', '',
3877 _('change working directory'), _('DIR')),
3880 _('change working directory'), _('DIR')),
3878 ('y', 'noninteractive', None,
3881 ('y', 'noninteractive', None,
3879 _('do not prompt, assume \'yes\' for any required answers')),
3882 _('do not prompt, assume \'yes\' for any required answers')),
3880 ('q', 'quiet', None, _('suppress output')),
3883 ('q', 'quiet', None, _('suppress output')),
3881 ('v', 'verbose', None, _('enable additional output')),
3884 ('v', 'verbose', None, _('enable additional output')),
3882 ('', 'config', [],
3885 ('', 'config', [],
3883 _('set/override config option (use \'section.name=value\')'),
3886 _('set/override config option (use \'section.name=value\')'),
3884 _('CONFIG')),
3887 _('CONFIG')),
3885 ('', 'debug', None, _('enable debugging output')),
3888 ('', 'debug', None, _('enable debugging output')),
3886 ('', 'debugger', None, _('start debugger')),
3889 ('', 'debugger', None, _('start debugger')),
3887 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3890 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3888 _('ENCODE')),
3891 _('ENCODE')),
3889 ('', 'encodingmode', encoding.encodingmode,
3892 ('', 'encodingmode', encoding.encodingmode,
3890 _('set the charset encoding mode'), _('MODE')),
3893 _('set the charset encoding mode'), _('MODE')),
3891 ('', 'traceback', None, _('always print a traceback on exception')),
3894 ('', 'traceback', None, _('always print a traceback on exception')),
3892 ('', 'time', None, _('time how long the command takes')),
3895 ('', 'time', None, _('time how long the command takes')),
3893 ('', 'profile', None, _('print command execution profile')),
3896 ('', 'profile', None, _('print command execution profile')),
3894 ('', 'version', None, _('output version information and exit')),
3897 ('', 'version', None, _('output version information and exit')),
3895 ('h', 'help', None, _('display help and exit')),
3898 ('h', 'help', None, _('display help and exit')),
3896 ]
3899 ]
3897
3900
3898 dryrunopts = [('n', 'dry-run', None,
3901 dryrunopts = [('n', 'dry-run', None,
3899 _('do not perform actions, just print output'))]
3902 _('do not perform actions, just print output'))]
3900
3903
3901 remoteopts = [
3904 remoteopts = [
3902 ('e', 'ssh', '',
3905 ('e', 'ssh', '',
3903 _('specify ssh command to use'), _('CMD')),
3906 _('specify ssh command to use'), _('CMD')),
3904 ('', 'remotecmd', '',
3907 ('', 'remotecmd', '',
3905 _('specify hg command to run on the remote side'), _('CMD')),
3908 _('specify hg command to run on the remote side'), _('CMD')),
3906 ]
3909 ]
3907
3910
3908 walkopts = [
3911 walkopts = [
3909 ('I', 'include', [],
3912 ('I', 'include', [],
3910 _('include names matching the given patterns'), _('PATTERN')),
3913 _('include names matching the given patterns'), _('PATTERN')),
3911 ('X', 'exclude', [],
3914 ('X', 'exclude', [],
3912 _('exclude names matching the given patterns'), _('PATTERN')),
3915 _('exclude names matching the given patterns'), _('PATTERN')),
3913 ]
3916 ]
3914
3917
3915 commitopts = [
3918 commitopts = [
3916 ('m', 'message', '',
3919 ('m', 'message', '',
3917 _('use text as commit message'), _('TEXT')),
3920 _('use text as commit message'), _('TEXT')),
3918 ('l', 'logfile', '',
3921 ('l', 'logfile', '',
3919 _('read commit message from file'), _('FILE')),
3922 _('read commit message from file'), _('FILE')),
3920 ]
3923 ]
3921
3924
3922 commitopts2 = [
3925 commitopts2 = [
3923 ('d', 'date', '',
3926 ('d', 'date', '',
3924 _('record datecode as commit date'), _('DATE')),
3927 _('record datecode as commit date'), _('DATE')),
3925 ('u', 'user', '',
3928 ('u', 'user', '',
3926 _('record the specified user as committer'), _('USER')),
3929 _('record the specified user as committer'), _('USER')),
3927 ]
3930 ]
3928
3931
3929 templateopts = [
3932 templateopts = [
3930 ('', 'style', '',
3933 ('', 'style', '',
3931 _('display using template map file'), _('STYLE')),
3934 _('display using template map file'), _('STYLE')),
3932 ('', 'template', '',
3935 ('', 'template', '',
3933 _('display with template'), _('TEMPLATE')),
3936 _('display with template'), _('TEMPLATE')),
3934 ]
3937 ]
3935
3938
3936 logopts = [
3939 logopts = [
3937 ('p', 'patch', None, _('show patch')),
3940 ('p', 'patch', None, _('show patch')),
3938 ('g', 'git', None, _('use git extended diff format')),
3941 ('g', 'git', None, _('use git extended diff format')),
3939 ('l', 'limit', '',
3942 ('l', 'limit', '',
3940 _('limit number of changes displayed'), _('NUM')),
3943 _('limit number of changes displayed'), _('NUM')),
3941 ('M', 'no-merges', None, _('do not show merges')),
3944 ('M', 'no-merges', None, _('do not show merges')),
3942 ('', 'stat', None, _('output diffstat-style summary of changes')),
3945 ('', 'stat', None, _('output diffstat-style summary of changes')),
3943 ] + templateopts
3946 ] + templateopts
3944
3947
3945 diffopts = [
3948 diffopts = [
3946 ('a', 'text', None, _('treat all files as text')),
3949 ('a', 'text', None, _('treat all files as text')),
3947 ('g', 'git', None, _('use git extended diff format')),
3950 ('g', 'git', None, _('use git extended diff format')),
3948 ('', 'nodates', None, _('omit dates from diff headers'))
3951 ('', 'nodates', None, _('omit dates from diff headers'))
3949 ]
3952 ]
3950
3953
3951 diffopts2 = [
3954 diffopts2 = [
3952 ('p', 'show-function', None, _('show which function each change is in')),
3955 ('p', 'show-function', None, _('show which function each change is in')),
3953 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3956 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3954 ('w', 'ignore-all-space', None,
3957 ('w', 'ignore-all-space', None,
3955 _('ignore white space when comparing lines')),
3958 _('ignore white space when comparing lines')),
3956 ('b', 'ignore-space-change', None,
3959 ('b', 'ignore-space-change', None,
3957 _('ignore changes in the amount of white space')),
3960 _('ignore changes in the amount of white space')),
3958 ('B', 'ignore-blank-lines', None,
3961 ('B', 'ignore-blank-lines', None,
3959 _('ignore changes whose lines are all blank')),
3962 _('ignore changes whose lines are all blank')),
3960 ('U', 'unified', '',
3963 ('U', 'unified', '',
3961 _('number of lines of context to show'), _('NUM')),
3964 _('number of lines of context to show'), _('NUM')),
3962 ('', 'stat', None, _('output diffstat-style summary of changes')),
3965 ('', 'stat', None, _('output diffstat-style summary of changes')),
3963 ]
3966 ]
3964
3967
3965 similarityopts = [
3968 similarityopts = [
3966 ('s', 'similarity', '',
3969 ('s', 'similarity', '',
3967 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3970 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3968 ]
3971 ]
3969
3972
3970 table = {
3973 table = {
3971 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3974 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3972 "addremove":
3975 "addremove":
3973 (addremove, similarityopts + walkopts + dryrunopts,
3976 (addremove, similarityopts + walkopts + dryrunopts,
3974 _('[OPTION]... [FILE]...')),
3977 _('[OPTION]... [FILE]...')),
3975 "^annotate|blame":
3978 "^annotate|blame":
3976 (annotate,
3979 (annotate,
3977 [('r', 'rev', '',
3980 [('r', 'rev', '',
3978 _('annotate the specified revision'), _('REV')),
3981 _('annotate the specified revision'), _('REV')),
3979 ('', 'follow', None,
3982 ('', 'follow', None,
3980 _('follow copies/renames and list the filename (DEPRECATED)')),
3983 _('follow copies/renames and list the filename (DEPRECATED)')),
3981 ('', 'no-follow', None, _("don't follow copies and renames")),
3984 ('', 'no-follow', None, _("don't follow copies and renames")),
3982 ('a', 'text', None, _('treat all files as text')),
3985 ('a', 'text', None, _('treat all files as text')),
3983 ('u', 'user', None, _('list the author (long with -v)')),
3986 ('u', 'user', None, _('list the author (long with -v)')),
3984 ('f', 'file', None, _('list the filename')),
3987 ('f', 'file', None, _('list the filename')),
3985 ('d', 'date', None, _('list the date (short with -q)')),
3988 ('d', 'date', None, _('list the date (short with -q)')),
3986 ('n', 'number', None, _('list the revision number (default)')),
3989 ('n', 'number', None, _('list the revision number (default)')),
3987 ('c', 'changeset', None, _('list the changeset')),
3990 ('c', 'changeset', None, _('list the changeset')),
3988 ('l', 'line-number', None,
3991 ('l', 'line-number', None,
3989 _('show line number at the first appearance'))
3992 _('show line number at the first appearance'))
3990 ] + walkopts,
3993 ] + walkopts,
3991 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3994 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3992 "archive":
3995 "archive":
3993 (archive,
3996 (archive,
3994 [('', 'no-decode', None, _('do not pass files through decoders')),
3997 [('', 'no-decode', None, _('do not pass files through decoders')),
3995 ('p', 'prefix', '',
3998 ('p', 'prefix', '',
3996 _('directory prefix for files in archive'), _('PREFIX')),
3999 _('directory prefix for files in archive'), _('PREFIX')),
3997 ('r', 'rev', '',
4000 ('r', 'rev', '',
3998 _('revision to distribute'), _('REV')),
4001 _('revision to distribute'), _('REV')),
3999 ('t', 'type', '',
4002 ('t', 'type', '',
4000 _('type of distribution to create'), _('TYPE')),
4003 _('type of distribution to create'), _('TYPE')),
4001 ] + walkopts,
4004 ] + walkopts,
4002 _('[OPTION]... DEST')),
4005 _('[OPTION]... DEST')),
4003 "backout":
4006 "backout":
4004 (backout,
4007 (backout,
4005 [('', 'merge', None,
4008 [('', 'merge', None,
4006 _('merge with old dirstate parent after backout')),
4009 _('merge with old dirstate parent after backout')),
4007 ('', 'parent', '',
4010 ('', 'parent', '',
4008 _('parent to choose when backing out merge'), _('REV')),
4011 _('parent to choose when backing out merge'), _('REV')),
4009 ('r', 'rev', '',
4012 ('r', 'rev', '',
4010 _('revision to backout'), _('REV')),
4013 _('revision to backout'), _('REV')),
4011 ] + walkopts + commitopts + commitopts2,
4014 ] + walkopts + commitopts + commitopts2,
4012 _('[OPTION]... [-r] REV')),
4015 _('[OPTION]... [-r] REV')),
4013 "bisect":
4016 "bisect":
4014 (bisect,
4017 (bisect,
4015 [('r', 'reset', False, _('reset bisect state')),
4018 [('r', 'reset', False, _('reset bisect state')),
4016 ('g', 'good', False, _('mark changeset good')),
4019 ('g', 'good', False, _('mark changeset good')),
4017 ('b', 'bad', False, _('mark changeset bad')),
4020 ('b', 'bad', False, _('mark changeset bad')),
4018 ('s', 'skip', False, _('skip testing changeset')),
4021 ('s', 'skip', False, _('skip testing changeset')),
4019 ('c', 'command', '',
4022 ('c', 'command', '',
4020 _('use command to check changeset state'), _('CMD')),
4023 _('use command to check changeset state'), _('CMD')),
4021 ('U', 'noupdate', False, _('do not update to target'))],
4024 ('U', 'noupdate', False, _('do not update to target'))],
4022 _("[-gbsr] [-U] [-c CMD] [REV]")),
4025 _("[-gbsr] [-U] [-c CMD] [REV]")),
4023 "branch":
4026 "branch":
4024 (branch,
4027 (branch,
4025 [('f', 'force', None,
4028 [('f', 'force', None,
4026 _('set branch name even if it shadows an existing branch')),
4029 _('set branch name even if it shadows an existing branch')),
4027 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4030 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4028 _('[-fC] [NAME]')),
4031 _('[-fC] [NAME]')),
4029 "branches":
4032 "branches":
4030 (branches,
4033 (branches,
4031 [('a', 'active', False,
4034 [('a', 'active', False,
4032 _('show only branches that have unmerged heads')),
4035 _('show only branches that have unmerged heads')),
4033 ('c', 'closed', False,
4036 ('c', 'closed', False,
4034 _('show normal and closed branches'))],
4037 _('show normal and closed branches'))],
4035 _('[-ac]')),
4038 _('[-ac]')),
4036 "bundle":
4039 "bundle":
4037 (bundle,
4040 (bundle,
4038 [('f', 'force', None,
4041 [('f', 'force', None,
4039 _('run even when the destination is unrelated')),
4042 _('run even when the destination is unrelated')),
4040 ('r', 'rev', [],
4043 ('r', 'rev', [],
4041 _('a changeset intended to be added to the destination'),
4044 _('a changeset intended to be added to the destination'),
4042 _('REV')),
4045 _('REV')),
4043 ('b', 'branch', [],
4046 ('b', 'branch', [],
4044 _('a specific branch you would like to bundle'),
4047 _('a specific branch you would like to bundle'),
4045 _('BRANCH')),
4048 _('BRANCH')),
4046 ('', 'base', [],
4049 ('', 'base', [],
4047 _('a base changeset assumed to be available at the destination'),
4050 _('a base changeset assumed to be available at the destination'),
4048 _('REV')),
4051 _('REV')),
4049 ('a', 'all', None, _('bundle all changesets in the repository')),
4052 ('a', 'all', None, _('bundle all changesets in the repository')),
4050 ('t', 'type', 'bzip2',
4053 ('t', 'type', 'bzip2',
4051 _('bundle compression type to use'), _('TYPE')),
4054 _('bundle compression type to use'), _('TYPE')),
4052 ] + remoteopts,
4055 ] + remoteopts,
4053 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4056 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4054 "cat":
4057 "cat":
4055 (cat,
4058 (cat,
4056 [('o', 'output', '',
4059 [('o', 'output', '',
4057 _('print output to file with formatted name'), _('FORMAT')),
4060 _('print output to file with formatted name'), _('FORMAT')),
4058 ('r', 'rev', '',
4061 ('r', 'rev', '',
4059 _('print the given revision'), _('REV')),
4062 _('print the given revision'), _('REV')),
4060 ('', 'decode', None, _('apply any matching decode filter')),
4063 ('', 'decode', None, _('apply any matching decode filter')),
4061 ] + walkopts,
4064 ] + walkopts,
4062 _('[OPTION]... FILE...')),
4065 _('[OPTION]... FILE...')),
4063 "^clone":
4066 "^clone":
4064 (clone,
4067 (clone,
4065 [('U', 'noupdate', None,
4068 [('U', 'noupdate', None,
4066 _('the clone will include an empty working copy (only a repository)')),
4069 _('the clone will include an empty working copy (only a repository)')),
4067 ('u', 'updaterev', '',
4070 ('u', 'updaterev', '',
4068 _('revision, tag or branch to check out'), _('REV')),
4071 _('revision, tag or branch to check out'), _('REV')),
4069 ('r', 'rev', [],
4072 ('r', 'rev', [],
4070 _('include the specified changeset'), _('REV')),
4073 _('include the specified changeset'), _('REV')),
4071 ('b', 'branch', [],
4074 ('b', 'branch', [],
4072 _('clone only the specified branch'), _('BRANCH')),
4075 _('clone only the specified branch'), _('BRANCH')),
4073 ('', 'pull', None, _('use pull protocol to copy metadata')),
4076 ('', 'pull', None, _('use pull protocol to copy metadata')),
4074 ('', 'uncompressed', None,
4077 ('', 'uncompressed', None,
4075 _('use uncompressed transfer (fast over LAN)')),
4078 _('use uncompressed transfer (fast over LAN)')),
4076 ] + remoteopts,
4079 ] + remoteopts,
4077 _('[OPTION]... SOURCE [DEST]')),
4080 _('[OPTION]... SOURCE [DEST]')),
4078 "^commit|ci":
4081 "^commit|ci":
4079 (commit,
4082 (commit,
4080 [('A', 'addremove', None,
4083 [('A', 'addremove', None,
4081 _('mark new/missing files as added/removed before committing')),
4084 _('mark new/missing files as added/removed before committing')),
4082 ('', 'close-branch', None,
4085 ('', 'close-branch', None,
4083 _('mark a branch as closed, hiding it from the branch list')),
4086 _('mark a branch as closed, hiding it from the branch list')),
4084 ] + walkopts + commitopts + commitopts2,
4087 ] + walkopts + commitopts + commitopts2,
4085 _('[OPTION]... [FILE]...')),
4088 _('[OPTION]... [FILE]...')),
4086 "copy|cp":
4089 "copy|cp":
4087 (copy,
4090 (copy,
4088 [('A', 'after', None, _('record a copy that has already occurred')),
4091 [('A', 'after', None, _('record a copy that has already occurred')),
4089 ('f', 'force', None,
4092 ('f', 'force', None,
4090 _('forcibly copy over an existing managed file')),
4093 _('forcibly copy over an existing managed file')),
4091 ] + walkopts + dryrunopts,
4094 ] + walkopts + dryrunopts,
4092 _('[OPTION]... [SOURCE]... DEST')),
4095 _('[OPTION]... [SOURCE]... DEST')),
4093 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4096 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4094 "debugbuilddag":
4097 "debugbuilddag":
4095 (debugbuilddag,
4098 (debugbuilddag,
4096 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4099 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4097 ('a', 'appended-file', None, _('add single file all revs append to')),
4100 ('a', 'appended-file', None, _('add single file all revs append to')),
4098 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4101 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4099 ('n', 'new-file', None, _('add new file at each rev')),
4102 ('n', 'new-file', None, _('add new file at each rev')),
4100 ],
4103 ],
4101 _('[OPTION]... TEXT')),
4104 _('[OPTION]... TEXT')),
4102 "debugcheckstate": (debugcheckstate, [], ''),
4105 "debugcheckstate": (debugcheckstate, [], ''),
4103 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4106 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4104 "debugcomplete":
4107 "debugcomplete":
4105 (debugcomplete,
4108 (debugcomplete,
4106 [('o', 'options', None, _('show the command options'))],
4109 [('o', 'options', None, _('show the command options'))],
4107 _('[-o] CMD')),
4110 _('[-o] CMD')),
4108 "debugdag":
4111 "debugdag":
4109 (debugdag,
4112 (debugdag,
4110 [('t', 'tags', None, _('use tags as labels')),
4113 [('t', 'tags', None, _('use tags as labels')),
4111 ('b', 'branches', None, _('annotate with branch names')),
4114 ('b', 'branches', None, _('annotate with branch names')),
4112 ('', 'dots', None, _('use dots for runs')),
4115 ('', 'dots', None, _('use dots for runs')),
4113 ('s', 'spaces', None, _('separate elements by spaces')),
4116 ('s', 'spaces', None, _('separate elements by spaces')),
4114 ],
4117 ],
4115 _('[OPTION]... [FILE [REV]...]')),
4118 _('[OPTION]... [FILE [REV]...]')),
4116 "debugdate":
4119 "debugdate":
4117 (debugdate,
4120 (debugdate,
4118 [('e', 'extended', None, _('try extended date formats'))],
4121 [('e', 'extended', None, _('try extended date formats'))],
4119 _('[-e] DATE [RANGE]')),
4122 _('[-e] DATE [RANGE]')),
4120 "debugdata": (debugdata, [], _('FILE REV')),
4123 "debugdata": (debugdata, [], _('FILE REV')),
4121 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4124 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4122 "debugindex": (debugindex, [], _('FILE')),
4125 "debugindex": (debugindex, [], _('FILE')),
4123 "debugindexdot": (debugindexdot, [], _('FILE')),
4126 "debugindexdot": (debugindexdot, [], _('FILE')),
4124 "debuginstall": (debuginstall, [], ''),
4127 "debuginstall": (debuginstall, [], ''),
4125 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4128 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4126 "debugrebuildstate":
4129 "debugrebuildstate":
4127 (debugrebuildstate,
4130 (debugrebuildstate,
4128 [('r', 'rev', '',
4131 [('r', 'rev', '',
4129 _('revision to rebuild to'), _('REV'))],
4132 _('revision to rebuild to'), _('REV'))],
4130 _('[-r REV] [REV]')),
4133 _('[-r REV] [REV]')),
4131 "debugrename":
4134 "debugrename":
4132 (debugrename,
4135 (debugrename,
4133 [('r', 'rev', '',
4136 [('r', 'rev', '',
4134 _('revision to debug'), _('REV'))],
4137 _('revision to debug'), _('REV'))],
4135 _('[-r REV] FILE')),
4138 _('[-r REV] FILE')),
4136 "debugrevspec":
4139 "debugrevspec":
4137 (debugrevspec, [], ('REVSPEC')),
4140 (debugrevspec, [], ('REVSPEC')),
4138 "debugsetparents":
4141 "debugsetparents":
4139 (debugsetparents, [], _('REV1 [REV2]')),
4142 (debugsetparents, [], _('REV1 [REV2]')),
4140 "debugstate":
4143 "debugstate":
4141 (debugstate,
4144 (debugstate,
4142 [('', 'nodates', None, _('do not display the saved mtime'))],
4145 [('', 'nodates', None, _('do not display the saved mtime'))],
4143 _('[OPTION]...')),
4146 _('[OPTION]...')),
4144 "debugsub":
4147 "debugsub":
4145 (debugsub,
4148 (debugsub,
4146 [('r', 'rev', '',
4149 [('r', 'rev', '',
4147 _('revision to check'), _('REV'))],
4150 _('revision to check'), _('REV'))],
4148 _('[-r REV] [REV]')),
4151 _('[-r REV] [REV]')),
4149 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4152 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4150 "^diff":
4153 "^diff":
4151 (diff,
4154 (diff,
4152 [('r', 'rev', [],
4155 [('r', 'rev', [],
4153 _('revision'), _('REV')),
4156 _('revision'), _('REV')),
4154 ('c', 'change', '',
4157 ('c', 'change', '',
4155 _('change made by revision'), _('REV'))
4158 _('change made by revision'), _('REV'))
4156 ] + diffopts + diffopts2 + walkopts,
4159 ] + diffopts + diffopts2 + walkopts,
4157 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4158 "^export":
4161 "^export":
4159 (export,
4162 (export,
4160 [('o', 'output', '',
4163 [('o', 'output', '',
4161 _('print output to file with formatted name'), _('FORMAT')),
4164 _('print output to file with formatted name'), _('FORMAT')),
4162 ('', 'switch-parent', None, _('diff against the second parent')),
4165 ('', 'switch-parent', None, _('diff against the second parent')),
4163 ('r', 'rev', [],
4166 ('r', 'rev', [],
4164 _('revisions to export'), _('REV')),
4167 _('revisions to export'), _('REV')),
4165 ] + diffopts,
4168 ] + diffopts,
4166 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4169 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4167 "^forget":
4170 "^forget":
4168 (forget,
4171 (forget,
4169 [] + walkopts,
4172 [] + walkopts,
4170 _('[OPTION]... FILE...')),
4173 _('[OPTION]... FILE...')),
4171 "grep":
4174 "grep":
4172 (grep,
4175 (grep,
4173 [('0', 'print0', None, _('end fields with NUL')),
4176 [('0', 'print0', None, _('end fields with NUL')),
4174 ('', 'all', None, _('print all revisions that match')),
4177 ('', 'all', None, _('print all revisions that match')),
4175 ('f', 'follow', None,
4178 ('f', 'follow', None,
4176 _('follow changeset history,'
4179 _('follow changeset history,'
4177 ' or file history across copies and renames')),
4180 ' or file history across copies and renames')),
4178 ('i', 'ignore-case', None, _('ignore case when matching')),
4181 ('i', 'ignore-case', None, _('ignore case when matching')),
4179 ('l', 'files-with-matches', None,
4182 ('l', 'files-with-matches', None,
4180 _('print only filenames and revisions that match')),
4183 _('print only filenames and revisions that match')),
4181 ('n', 'line-number', None, _('print matching line numbers')),
4184 ('n', 'line-number', None, _('print matching line numbers')),
4182 ('r', 'rev', [],
4185 ('r', 'rev', [],
4183 _('only search files changed within revision range'), _('REV')),
4186 _('only search files changed within revision range'), _('REV')),
4184 ('u', 'user', None, _('list the author (long with -v)')),
4187 ('u', 'user', None, _('list the author (long with -v)')),
4185 ('d', 'date', None, _('list the date (short with -q)')),
4188 ('d', 'date', None, _('list the date (short with -q)')),
4186 ] + walkopts,
4189 ] + walkopts,
4187 _('[OPTION]... PATTERN [FILE]...')),
4190 _('[OPTION]... PATTERN [FILE]...')),
4188 "heads":
4191 "heads":
4189 (heads,
4192 (heads,
4190 [('r', 'rev', '',
4193 [('r', 'rev', '',
4191 _('show only heads which are descendants of REV'), _('REV')),
4194 _('show only heads which are descendants of REV'), _('REV')),
4192 ('t', 'topo', False, _('show topological heads only')),
4195 ('t', 'topo', False, _('show topological heads only')),
4193 ('a', 'active', False,
4196 ('a', 'active', False,
4194 _('show active branchheads only (DEPRECATED)')),
4197 _('show active branchheads only (DEPRECATED)')),
4195 ('c', 'closed', False,
4198 ('c', 'closed', False,
4196 _('show normal and closed branch heads')),
4199 _('show normal and closed branch heads')),
4197 ] + templateopts,
4200 ] + templateopts,
4198 _('[-ac] [-r REV] [REV]...')),
4201 _('[-ac] [-r REV] [REV]...')),
4199 "help": (help_, [], _('[TOPIC]')),
4202 "help": (help_, [], _('[TOPIC]')),
4200 "identify|id":
4203 "identify|id":
4201 (identify,
4204 (identify,
4202 [('r', 'rev', '',
4205 [('r', 'rev', '',
4203 _('identify the specified revision'), _('REV')),
4206 _('identify the specified revision'), _('REV')),
4204 ('n', 'num', None, _('show local revision number')),
4207 ('n', 'num', None, _('show local revision number')),
4205 ('i', 'id', None, _('show global revision id')),
4208 ('i', 'id', None, _('show global revision id')),
4206 ('b', 'branch', None, _('show branch')),
4209 ('b', 'branch', None, _('show branch')),
4207 ('t', 'tags', None, _('show tags'))],
4210 ('t', 'tags', None, _('show tags'))],
4208 _('[-nibt] [-r REV] [SOURCE]')),
4211 _('[-nibt] [-r REV] [SOURCE]')),
4209 "import|patch":
4212 "import|patch":
4210 (import_,
4213 (import_,
4211 [('p', 'strip', 1,
4214 [('p', 'strip', 1,
4212 _('directory strip option for patch. This has the same '
4215 _('directory strip option for patch. This has the same '
4213 'meaning as the corresponding patch option'),
4216 'meaning as the corresponding patch option'),
4214 _('NUM')),
4217 _('NUM')),
4215 ('b', 'base', '',
4218 ('b', 'base', '',
4216 _('base path'), _('PATH')),
4219 _('base path'), _('PATH')),
4217 ('f', 'force', None,
4220 ('f', 'force', None,
4218 _('skip check for outstanding uncommitted changes')),
4221 _('skip check for outstanding uncommitted changes')),
4219 ('', 'no-commit', None,
4222 ('', 'no-commit', None,
4220 _("don't commit, just update the working directory")),
4223 _("don't commit, just update the working directory")),
4221 ('', 'exact', None,
4224 ('', 'exact', None,
4222 _('apply patch to the nodes from which it was generated')),
4225 _('apply patch to the nodes from which it was generated')),
4223 ('', 'import-branch', None,
4226 ('', 'import-branch', None,
4224 _('use any branch information in patch (implied by --exact)'))] +
4227 _('use any branch information in patch (implied by --exact)'))] +
4225 commitopts + commitopts2 + similarityopts,
4228 commitopts + commitopts2 + similarityopts,
4226 _('[OPTION]... PATCH...')),
4229 _('[OPTION]... PATCH...')),
4227 "incoming|in":
4230 "incoming|in":
4228 (incoming,
4231 (incoming,
4229 [('f', 'force', None,
4232 [('f', 'force', None,
4230 _('run even if remote repository is unrelated')),
4233 _('run even if remote repository is unrelated')),
4231 ('n', 'newest-first', None, _('show newest record first')),
4234 ('n', 'newest-first', None, _('show newest record first')),
4232 ('', 'bundle', '',
4235 ('', 'bundle', '',
4233 _('file to store the bundles into'), _('FILE')),
4236 _('file to store the bundles into'), _('FILE')),
4234 ('r', 'rev', [],
4237 ('r', 'rev', [],
4235 _('a remote changeset intended to be added'), _('REV')),
4238 _('a remote changeset intended to be added'), _('REV')),
4236 ('b', 'branch', [],
4239 ('b', 'branch', [],
4237 _('a specific branch you would like to pull'), _('BRANCH')),
4240 _('a specific branch you would like to pull'), _('BRANCH')),
4238 ] + logopts + remoteopts,
4241 ] + logopts + remoteopts,
4239 _('[-p] [-n] [-M] [-f] [-r REV]...'
4242 _('[-p] [-n] [-M] [-f] [-r REV]...'
4240 ' [--bundle FILENAME] [SOURCE]')),
4243 ' [--bundle FILENAME] [SOURCE]')),
4241 "^init":
4244 "^init":
4242 (init,
4245 (init,
4243 remoteopts,
4246 remoteopts,
4244 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4247 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4245 "locate":
4248 "locate":
4246 (locate,
4249 (locate,
4247 [('r', 'rev', '',
4250 [('r', 'rev', '',
4248 _('search the repository as it is in REV'), _('REV')),
4251 _('search the repository as it is in REV'), _('REV')),
4249 ('0', 'print0', None,
4252 ('0', 'print0', None,
4250 _('end filenames with NUL, for use with xargs')),
4253 _('end filenames with NUL, for use with xargs')),
4251 ('f', 'fullpath', None,
4254 ('f', 'fullpath', None,
4252 _('print complete paths from the filesystem root')),
4255 _('print complete paths from the filesystem root')),
4253 ] + walkopts,
4256 ] + walkopts,
4254 _('[OPTION]... [PATTERN]...')),
4257 _('[OPTION]... [PATTERN]...')),
4255 "^log|history":
4258 "^log|history":
4256 (log,
4259 (log,
4257 [('f', 'follow', None,
4260 [('f', 'follow', None,
4258 _('follow changeset history,'
4261 _('follow changeset history,'
4259 ' or file history across copies and renames')),
4262 ' or file history across copies and renames')),
4260 ('', 'follow-first', None,
4263 ('', 'follow-first', None,
4261 _('only follow the first parent of merge changesets')),
4264 _('only follow the first parent of merge changesets')),
4262 ('d', 'date', '',
4265 ('d', 'date', '',
4263 _('show revisions matching date spec'), _('DATE')),
4266 _('show revisions matching date spec'), _('DATE')),
4264 ('C', 'copies', None, _('show copied files')),
4267 ('C', 'copies', None, _('show copied files')),
4265 ('k', 'keyword', [],
4268 ('k', 'keyword', [],
4266 _('do case-insensitive search for a given text'), _('TEXT')),
4269 _('do case-insensitive search for a given text'), _('TEXT')),
4267 ('r', 'rev', [],
4270 ('r', 'rev', [],
4268 _('show the specified revision or range'), _('REV')),
4271 _('show the specified revision or range'), _('REV')),
4269 ('', 'removed', None, _('include revisions where files were removed')),
4272 ('', 'removed', None, _('include revisions where files were removed')),
4270 ('m', 'only-merges', None, _('show only merges')),
4273 ('m', 'only-merges', None, _('show only merges')),
4271 ('u', 'user', [],
4274 ('u', 'user', [],
4272 _('revisions committed by user'), _('USER')),
4275 _('revisions committed by user'), _('USER')),
4273 ('', 'only-branch', [],
4276 ('', 'only-branch', [],
4274 _('show only changesets within the given named branch (DEPRECATED)'),
4277 _('show only changesets within the given named branch (DEPRECATED)'),
4275 _('BRANCH')),
4278 _('BRANCH')),
4276 ('b', 'branch', [],
4279 ('b', 'branch', [],
4277 _('show changesets within the given named branch'), _('BRANCH')),
4280 _('show changesets within the given named branch'), _('BRANCH')),
4278 ('P', 'prune', [],
4281 ('P', 'prune', [],
4279 _('do not display revision or any of its ancestors'), _('REV')),
4282 _('do not display revision or any of its ancestors'), _('REV')),
4280 ] + logopts + walkopts,
4283 ] + logopts + walkopts,
4281 _('[OPTION]... [FILE]')),
4284 _('[OPTION]... [FILE]')),
4282 "manifest":
4285 "manifest":
4283 (manifest,
4286 (manifest,
4284 [('r', 'rev', '',
4287 [('r', 'rev', '',
4285 _('revision to display'), _('REV'))],
4288 _('revision to display'), _('REV'))],
4286 _('[-r REV]')),
4289 _('[-r REV]')),
4287 "^merge":
4290 "^merge":
4288 (merge,
4291 (merge,
4289 [('f', 'force', None, _('force a merge with outstanding changes')),
4292 [('f', 'force', None, _('force a merge with outstanding changes')),
4290 ('r', 'rev', '',
4293 ('r', 'rev', '',
4291 _('revision to merge'), _('REV')),
4294 _('revision to merge'), _('REV')),
4292 ('P', 'preview', None,
4295 ('P', 'preview', None,
4293 _('review revisions to merge (no merge is performed)'))],
4296 _('review revisions to merge (no merge is performed)'))],
4294 _('[-P] [-f] [[-r] REV]')),
4297 _('[-P] [-f] [[-r] REV]')),
4295 "outgoing|out":
4298 "outgoing|out":
4296 (outgoing,
4299 (outgoing,
4297 [('f', 'force', None,
4300 [('f', 'force', None,
4298 _('run even when the destination is unrelated')),
4301 _('run even when the destination is unrelated')),
4299 ('r', 'rev', [],
4302 ('r', 'rev', [],
4300 _('a changeset intended to be included in the destination'),
4303 _('a changeset intended to be included in the destination'),
4301 _('REV')),
4304 _('REV')),
4302 ('n', 'newest-first', None, _('show newest record first')),
4305 ('n', 'newest-first', None, _('show newest record first')),
4303 ('b', 'branch', [],
4306 ('b', 'branch', [],
4304 _('a specific branch you would like to push'), _('BRANCH')),
4307 _('a specific branch you would like to push'), _('BRANCH')),
4305 ] + logopts + remoteopts,
4308 ] + logopts + remoteopts,
4306 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4309 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4307 "parents":
4310 "parents":
4308 (parents,
4311 (parents,
4309 [('r', 'rev', '',
4312 [('r', 'rev', '',
4310 _('show parents of the specified revision'), _('REV')),
4313 _('show parents of the specified revision'), _('REV')),
4311 ] + templateopts,
4314 ] + templateopts,
4312 _('[-r REV] [FILE]')),
4315 _('[-r REV] [FILE]')),
4313 "paths": (paths, [], _('[NAME]')),
4316 "paths": (paths, [], _('[NAME]')),
4314 "^pull":
4317 "^pull":
4315 (pull,
4318 (pull,
4316 [('u', 'update', None,
4319 [('u', 'update', None,
4317 _('update to new branch head if changesets were pulled')),
4320 _('update to new branch head if changesets were pulled')),
4318 ('f', 'force', None,
4321 ('f', 'force', None,
4319 _('run even when remote repository is unrelated')),
4322 _('run even when remote repository is unrelated')),
4320 ('r', 'rev', [],
4323 ('r', 'rev', [],
4321 _('a remote changeset intended to be added'), _('REV')),
4324 _('a remote changeset intended to be added'), _('REV')),
4322 ('b', 'branch', [],
4325 ('b', 'branch', [],
4323 _('a specific branch you would like to pull'), _('BRANCH')),
4326 _('a specific branch you would like to pull'), _('BRANCH')),
4324 ] + remoteopts,
4327 ] + remoteopts,
4325 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4328 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4326 "^push":
4329 "^push":
4327 (push,
4330 (push,
4328 [('f', 'force', None, _('force push')),
4331 [('f', 'force', None, _('force push')),
4329 ('r', 'rev', [],
4332 ('r', 'rev', [],
4330 _('a changeset intended to be included in the destination'),
4333 _('a changeset intended to be included in the destination'),
4331 _('REV')),
4334 _('REV')),
4332 ('b', 'branch', [],
4335 ('b', 'branch', [],
4333 _('a specific branch you would like to push'), _('BRANCH')),
4336 _('a specific branch you would like to push'), _('BRANCH')),
4334 ('', 'new-branch', False, _('allow pushing a new branch')),
4337 ('', 'new-branch', False, _('allow pushing a new branch')),
4335 ] + remoteopts,
4338 ] + remoteopts,
4336 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4339 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4337 "recover": (recover, []),
4340 "recover": (recover, []),
4338 "^remove|rm":
4341 "^remove|rm":
4339 (remove,
4342 (remove,
4340 [('A', 'after', None, _('record delete for missing files')),
4343 [('A', 'after', None, _('record delete for missing files')),
4341 ('f', 'force', None,
4344 ('f', 'force', None,
4342 _('remove (and delete) file even if added or modified')),
4345 _('remove (and delete) file even if added or modified')),
4343 ] + walkopts,
4346 ] + walkopts,
4344 _('[OPTION]... FILE...')),
4347 _('[OPTION]... FILE...')),
4345 "rename|mv":
4348 "rename|mv":
4346 (rename,
4349 (rename,
4347 [('A', 'after', None, _('record a rename that has already occurred')),
4350 [('A', 'after', None, _('record a rename that has already occurred')),
4348 ('f', 'force', None,
4351 ('f', 'force', None,
4349 _('forcibly copy over an existing managed file')),
4352 _('forcibly copy over an existing managed file')),
4350 ] + walkopts + dryrunopts,
4353 ] + walkopts + dryrunopts,
4351 _('[OPTION]... SOURCE... DEST')),
4354 _('[OPTION]... SOURCE... DEST')),
4352 "resolve":
4355 "resolve":
4353 (resolve,
4356 (resolve,
4354 [('a', 'all', None, _('select all unresolved files')),
4357 [('a', 'all', None, _('select all unresolved files')),
4355 ('l', 'list', None, _('list state of files needing merge')),
4358 ('l', 'list', None, _('list state of files needing merge')),
4356 ('m', 'mark', None, _('mark files as resolved')),
4359 ('m', 'mark', None, _('mark files as resolved')),
4357 ('u', 'unmark', None, _('mark files as unresolved')),
4360 ('u', 'unmark', None, _('mark files as unresolved')),
4358 ('n', 'no-status', None, _('hide status prefix'))]
4361 ('n', 'no-status', None, _('hide status prefix'))]
4359 + walkopts,
4362 + walkopts,
4360 _('[OPTION]... [FILE]...')),
4363 _('[OPTION]... [FILE]...')),
4361 "revert":
4364 "revert":
4362 (revert,
4365 (revert,
4363 [('a', 'all', None, _('revert all changes when no arguments given')),
4366 [('a', 'all', None, _('revert all changes when no arguments given')),
4364 ('d', 'date', '',
4367 ('d', 'date', '',
4365 _('tipmost revision matching date'), _('DATE')),
4368 _('tipmost revision matching date'), _('DATE')),
4366 ('r', 'rev', '',
4369 ('r', 'rev', '',
4367 _('revert to the specified revision'), _('REV')),
4370 _('revert to the specified revision'), _('REV')),
4368 ('', 'no-backup', None, _('do not save backup copies of files')),
4371 ('', 'no-backup', None, _('do not save backup copies of files')),
4369 ] + walkopts + dryrunopts,
4372 ] + walkopts + dryrunopts,
4370 _('[OPTION]... [-r REV] [NAME]...')),
4373 _('[OPTION]... [-r REV] [NAME]...')),
4371 "rollback": (rollback, dryrunopts),
4374 "rollback": (rollback, dryrunopts),
4372 "root": (root, []),
4375 "root": (root, []),
4373 "^serve":
4376 "^serve":
4374 (serve,
4377 (serve,
4375 [('A', 'accesslog', '',
4378 [('A', 'accesslog', '',
4376 _('name of access log file to write to'), _('FILE')),
4379 _('name of access log file to write to'), _('FILE')),
4377 ('d', 'daemon', None, _('run server in background')),
4380 ('d', 'daemon', None, _('run server in background')),
4378 ('', 'daemon-pipefds', '',
4381 ('', 'daemon-pipefds', '',
4379 _('used internally by daemon mode'), _('NUM')),
4382 _('used internally by daemon mode'), _('NUM')),
4380 ('E', 'errorlog', '',
4383 ('E', 'errorlog', '',
4381 _('name of error log file to write to'), _('FILE')),
4384 _('name of error log file to write to'), _('FILE')),
4382 # use string type, then we can check if something was passed
4385 # use string type, then we can check if something was passed
4383 ('p', 'port', '',
4386 ('p', 'port', '',
4384 _('port to listen on (default: 8000)'), _('PORT')),
4387 _('port to listen on (default: 8000)'), _('PORT')),
4385 ('a', 'address', '',
4388 ('a', 'address', '',
4386 _('address to listen on (default: all interfaces)'), _('ADDR')),
4389 _('address to listen on (default: all interfaces)'), _('ADDR')),
4387 ('', 'prefix', '',
4390 ('', 'prefix', '',
4388 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4391 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4389 ('n', 'name', '',
4392 ('n', 'name', '',
4390 _('name to show in web pages (default: working directory)'),
4393 _('name to show in web pages (default: working directory)'),
4391 _('NAME')),
4394 _('NAME')),
4392 ('', 'web-conf', '',
4395 ('', 'web-conf', '',
4393 _('name of the hgweb config file (serve more than one repository)'),
4396 _('name of the hgweb config file (serve more than one repository)'),
4394 _('FILE')),
4397 _('FILE')),
4395 ('', 'webdir-conf', '',
4398 ('', 'webdir-conf', '',
4396 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4399 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4397 ('', 'pid-file', '',
4400 ('', 'pid-file', '',
4398 _('name of file to write process ID to'), _('FILE')),
4401 _('name of file to write process ID to'), _('FILE')),
4399 ('', 'stdio', None, _('for remote clients')),
4402 ('', 'stdio', None, _('for remote clients')),
4400 ('t', 'templates', '',
4403 ('t', 'templates', '',
4401 _('web templates to use'), _('TEMPLATE')),
4404 _('web templates to use'), _('TEMPLATE')),
4402 ('', 'style', '',
4405 ('', 'style', '',
4403 _('template style to use'), _('STYLE')),
4406 _('template style to use'), _('STYLE')),
4404 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4407 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4405 ('', 'certificate', '',
4408 ('', 'certificate', '',
4406 _('SSL certificate file'), _('FILE'))],
4409 _('SSL certificate file'), _('FILE'))],
4407 _('[OPTION]...')),
4410 _('[OPTION]...')),
4408 "showconfig|debugconfig":
4411 "showconfig|debugconfig":
4409 (showconfig,
4412 (showconfig,
4410 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4413 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4411 _('[-u] [NAME]...')),
4414 _('[-u] [NAME]...')),
4412 "^summary|sum":
4415 "^summary|sum":
4413 (summary,
4416 (summary,
4414 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4417 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4415 "^status|st":
4418 "^status|st":
4416 (status,
4419 (status,
4417 [('A', 'all', None, _('show status of all files')),
4420 [('A', 'all', None, _('show status of all files')),
4418 ('m', 'modified', None, _('show only modified files')),
4421 ('m', 'modified', None, _('show only modified files')),
4419 ('a', 'added', None, _('show only added files')),
4422 ('a', 'added', None, _('show only added files')),
4420 ('r', 'removed', None, _('show only removed files')),
4423 ('r', 'removed', None, _('show only removed files')),
4421 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4424 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4422 ('c', 'clean', None, _('show only files without changes')),
4425 ('c', 'clean', None, _('show only files without changes')),
4423 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4426 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4424 ('i', 'ignored', None, _('show only ignored files')),
4427 ('i', 'ignored', None, _('show only ignored files')),
4425 ('n', 'no-status', None, _('hide status prefix')),
4428 ('n', 'no-status', None, _('hide status prefix')),
4426 ('C', 'copies', None, _('show source of copied files')),
4429 ('C', 'copies', None, _('show source of copied files')),
4427 ('0', 'print0', None,
4430 ('0', 'print0', None,
4428 _('end filenames with NUL, for use with xargs')),
4431 _('end filenames with NUL, for use with xargs')),
4429 ('', 'rev', [],
4432 ('', 'rev', [],
4430 _('show difference from revision'), _('REV')),
4433 _('show difference from revision'), _('REV')),
4431 ('', 'change', '',
4434 ('', 'change', '',
4432 _('list the changed files of a revision'), _('REV')),
4435 _('list the changed files of a revision'), _('REV')),
4433 ] + walkopts,
4436 ] + walkopts,
4434 _('[OPTION]... [FILE]...')),
4437 _('[OPTION]... [FILE]...')),
4435 "tag":
4438 "tag":
4436 (tag,
4439 (tag,
4437 [('f', 'force', None, _('replace existing tag')),
4440 [('f', 'force', None, _('replace existing tag')),
4438 ('l', 'local', None, _('make the tag local')),
4441 ('l', 'local', None, _('make the tag local')),
4439 ('r', 'rev', '',
4442 ('r', 'rev', '',
4440 _('revision to tag'), _('REV')),
4443 _('revision to tag'), _('REV')),
4441 ('', 'remove', None, _('remove a tag')),
4444 ('', 'remove', None, _('remove a tag')),
4442 # -l/--local is already there, commitopts cannot be used
4445 # -l/--local is already there, commitopts cannot be used
4443 ('e', 'edit', None, _('edit commit message')),
4446 ('e', 'edit', None, _('edit commit message')),
4444 ('m', 'message', '',
4447 ('m', 'message', '',
4445 _('use <text> as commit message'), _('TEXT')),
4448 _('use <text> as commit message'), _('TEXT')),
4446 ] + commitopts2,
4449 ] + commitopts2,
4447 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4450 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4448 "tags": (tags, [], ''),
4451 "tags": (tags, [], ''),
4449 "tip":
4452 "tip":
4450 (tip,
4453 (tip,
4451 [('p', 'patch', None, _('show patch')),
4454 [('p', 'patch', None, _('show patch')),
4452 ('g', 'git', None, _('use git extended diff format')),
4455 ('g', 'git', None, _('use git extended diff format')),
4453 ] + templateopts,
4456 ] + templateopts,
4454 _('[-p] [-g]')),
4457 _('[-p] [-g]')),
4455 "unbundle":
4458 "unbundle":
4456 (unbundle,
4459 (unbundle,
4457 [('u', 'update', None,
4460 [('u', 'update', None,
4458 _('update to new branch head if changesets were unbundled'))],
4461 _('update to new branch head if changesets were unbundled'))],
4459 _('[-u] FILE...')),
4462 _('[-u] FILE...')),
4460 "^update|up|checkout|co":
4463 "^update|up|checkout|co":
4461 (update,
4464 (update,
4462 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4465 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4463 ('c', 'check', None, _('check for uncommitted changes')),
4466 ('c', 'check', None, _('check for uncommitted changes')),
4464 ('d', 'date', '',
4467 ('d', 'date', '',
4465 _('tipmost revision matching date'), _('DATE')),
4468 _('tipmost revision matching date'), _('DATE')),
4466 ('r', 'rev', '',
4469 ('r', 'rev', '',
4467 _('revision'), _('REV'))],
4470 _('revision'), _('REV'))],
4468 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4471 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4469 "verify": (verify, []),
4472 "verify": (verify, []),
4470 "version": (version_, []),
4473 "version": (version_, []),
4471 }
4474 }
4472
4475
4473 norepo = ("clone init version help debugcommands debugcomplete debugdata"
4476 norepo = ("clone init version help debugcommands debugcomplete debugdata"
4474 " debugindex debugindexdot debugdate debuginstall debugfsinfo"
4477 " debugindex debugindexdot debugdate debuginstall debugfsinfo"
4475 " debugpushkey")
4478 " debugpushkey")
4476 optionalrepo = ("identify paths serve showconfig debugancestor debugdag")
4479 optionalrepo = ("identify paths serve showconfig debugancestor debugdag")
@@ -1,29 +1,29 b''
1 Mercurial's default format for showing changes between two versions of
1 Mercurial's default format for showing changes between two versions of
2 a file is compatible with the unified format of GNU diff, which can be
2 a file is compatible with the unified format of GNU diff, which can be
3 used by GNU patch and many other standard tools.
3 used by GNU patch and many other standard tools.
4
4
5 While this standard format is often enough, it does not encode the
5 While this standard format is often enough, it does not encode the
6 following information:
6 following information:
7
7
8 - executable status and other permission bits
8 - executable status and other permission bits
9 - copy or rename information
9 - copy or rename information
10 - changes in binary files
10 - changes in binary files
11 - creation or deletion of empty files
11 - creation or deletion of empty files
12
12
13 Mercurial also supports the extended diff format from the git VCS
13 Mercurial also supports the extended diff format from the git VCS
14 which addresses these limitations. The git diff format is not produced
14 which addresses these limitations. The git diff format is not produced
15 by default because a few widespread tools still do not understand this
15 by default because a few widespread tools still do not understand this
16 format.
16 format.
17
17
18 This means that when generating diffs from a Mercurial repository
18 This means that when generating diffs from a Mercurial repository
19 (e.g. with :hg:`export`), you should be careful about things like file
19 (e.g. with :hg:`export`), you should be careful about things like file
20 copies and renames or other things mentioned above, because when
20 copies and renames or other things mentioned above, because when
21 applying a standard diff to a different repository, this extra
21 applying a standard diff to a different repository, this extra
22 information is lost. Mercurial's internal operations (like push and
22 information is lost. Mercurial's internal operations (like push and
23 pull) are not affected by this, because they use an internal binary
23 pull) are not affected by this, because they use an internal binary
24 format for communicating changes.
24 format for communicating changes.
25
25
26 To make Mercurial produce the git extended diff format, use the --git
26 To make Mercurial produce the git extended diff format, use the --git
27 option available for many commands, or set 'git = True' in the [diff]
27 option available for many commands, or set 'git = True' in the [diff]
28 section of your hgrc. You do not need to set this option when
28 section of your configuration file. You do not need to set this option
29 importing diffs in this format or using them in the mq extension.
29 when importing diffs in this format or using them in the mq extension.
@@ -1,86 +1,86 b''
1 HG
1 HG
2 Path to the 'hg' executable, automatically passed when running
2 Path to the 'hg' executable, automatically passed when running
3 hooks, extensions or external tools. If unset or empty, this is
3 hooks, extensions or external tools. If unset or empty, this is
4 the hg executable's name if it's frozen, or an executable named
4 the hg executable's name if it's frozen, or an executable named
5 'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
5 'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
6 Windows) is searched.
6 Windows) is searched.
7
7
8 HGEDITOR
8 HGEDITOR
9 This is the name of the editor to run when committing. See EDITOR.
9 This is the name of the editor to run when committing. See EDITOR.
10
10
11 (deprecated, use .hgrc)
11 (deprecated, use configuration file)
12
12
13 HGENCODING
13 HGENCODING
14 This overrides the default locale setting detected by Mercurial.
14 This overrides the default locale setting detected by Mercurial.
15 This setting is used to convert data including usernames,
15 This setting is used to convert data including usernames,
16 changeset descriptions, tag names, and branches. This setting can
16 changeset descriptions, tag names, and branches. This setting can
17 be overridden with the --encoding command-line option.
17 be overridden with the --encoding command-line option.
18
18
19 HGENCODINGMODE
19 HGENCODINGMODE
20 This sets Mercurial's behavior for handling unknown characters
20 This sets Mercurial's behavior for handling unknown characters
21 while transcoding user input. The default is "strict", which
21 while transcoding user input. The default is "strict", which
22 causes Mercurial to abort if it can't map a character. Other
22 causes Mercurial to abort if it can't map a character. Other
23 settings include "replace", which replaces unknown characters, and
23 settings include "replace", which replaces unknown characters, and
24 "ignore", which drops them. This setting can be overridden with
24 "ignore", which drops them. This setting can be overridden with
25 the --encodingmode command-line option.
25 the --encodingmode command-line option.
26
26
27 HGMERGE
27 HGMERGE
28 An executable to use for resolving merge conflicts. The program
28 An executable to use for resolving merge conflicts. The program
29 will be executed with three arguments: local file, remote file,
29 will be executed with three arguments: local file, remote file,
30 ancestor file.
30 ancestor file.
31
31
32 (deprecated, use .hgrc)
32 (deprecated, use configuration file)
33
33
34 HGRCPATH
34 HGRCPATH
35 A list of files or directories to search for hgrc files. Item
35 A list of files or directories to search for configuration
36 separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
36 files. Item separator is ":" on Unix, ";" on Windows. If HGRCPATH
37 platform default search path is used. If empty, only the .hg/hgrc
37 is not set, platform default search path is used. If empty, only
38 from the current repository is read.
38 the .hg/hgrc from the current repository is read.
39
39
40 For each element in HGRCPATH:
40 For each element in HGRCPATH:
41
41
42 - if it's a directory, all files ending with .rc are added
42 - if it's a directory, all files ending with .rc are added
43 - otherwise, the file itself will be added
43 - otherwise, the file itself will be added
44
44
45 HGPLAIN
45 HGPLAIN
46 When set, this disables any options in .hgrc that might change
46 When set, this disables any configuration settings that might
47 Mercurial's default output. This includes encoding, defaults,
47 change Mercurial's default output. This includes encoding,
48 verbose mode, debug mode, quiet mode, tracebacks, and
48 defaults, verbose mode, debug mode, quiet mode, tracebacks, and
49 localization. This can be useful when scripting against Mercurial
49 localization. This can be useful when scripting against Mercurial
50 in the face of existing user configuration.
50 in the face of existing user configuration.
51
51
52 Equivalent options set via command line flags or environment
52 Equivalent options set via command line flags or environment
53 variables are not overridden.
53 variables are not overridden.
54
54
55 HGUSER
55 HGUSER
56 This is the string used as the author of a commit. If not set,
56 This is the string used as the author of a commit. If not set,
57 available values will be considered in this order:
57 available values will be considered in this order:
58
58
59 - HGUSER (deprecated)
59 - HGUSER (deprecated)
60 - hgrc files from the HGRCPATH
60 - configuration files from the HGRCPATH
61 - EMAIL
61 - EMAIL
62 - interactive prompt
62 - interactive prompt
63 - LOGNAME (with ``@hostname`` appended)
63 - LOGNAME (with ``@hostname`` appended)
64
64
65 (deprecated, use .hgrc)
65 (deprecated, use configuration file)
66
66
67 EMAIL
67 EMAIL
68 May be used as the author of a commit; see HGUSER.
68 May be used as the author of a commit; see HGUSER.
69
69
70 LOGNAME
70 LOGNAME
71 May be used as the author of a commit; see HGUSER.
71 May be used as the author of a commit; see HGUSER.
72
72
73 VISUAL
73 VISUAL
74 This is the name of the editor to use when committing. See EDITOR.
74 This is the name of the editor to use when committing. See EDITOR.
75
75
76 EDITOR
76 EDITOR
77 Sometimes Mercurial needs to open a text file in an editor for a
77 Sometimes Mercurial needs to open a text file in an editor for a
78 user to modify, for example when writing commit messages. The
78 user to modify, for example when writing commit messages. The
79 editor it uses is determined by looking at the environment
79 editor it uses is determined by looking at the environment
80 variables HGEDITOR, VISUAL and EDITOR, in that order. The first
80 variables HGEDITOR, VISUAL and EDITOR, in that order. The first
81 non-empty one is chosen. If all of them are empty, the editor
81 non-empty one is chosen. If all of them are empty, the editor
82 defaults to 'vi'.
82 defaults to 'vi'.
83
83
84 PYTHONPATH
84 PYTHONPATH
85 This is used by Python to find imported modules and may need to be
85 This is used by Python to find imported modules and may need to be
86 set appropriately if this Mercurial is not installed system-wide.
86 set appropriately if this Mercurial is not installed system-wide.
@@ -1,33 +1,33 b''
1 Mercurial has the ability to add new features through the use of
1 Mercurial has the ability to add new features through the use of
2 extensions. Extensions may add new commands, add options to
2 extensions. Extensions may add new commands, add options to
3 existing commands, change the default behavior of commands, or
3 existing commands, change the default behavior of commands, or
4 implement hooks.
4 implement hooks.
5
5
6 Extensions are not loaded by default for a variety of reasons:
6 Extensions are not loaded by default for a variety of reasons:
7 they can increase startup overhead; they may be meant for advanced
7 they can increase startup overhead; they may be meant for advanced
8 usage only; they may provide potentially dangerous abilities (such
8 usage only; they may provide potentially dangerous abilities (such
9 as letting you destroy or modify history); they might not be ready
9 as letting you destroy or modify history); they might not be ready
10 for prime time; or they may alter some usual behaviors of stock
10 for prime time; or they may alter some usual behaviors of stock
11 Mercurial. It is thus up to the user to activate extensions as
11 Mercurial. It is thus up to the user to activate extensions as
12 needed.
12 needed.
13
13
14 To enable the "foo" extension, either shipped with Mercurial or in
14 To enable the "foo" extension, either shipped with Mercurial or in the
15 the Python search path, create an entry for it in your hgrc, like
15 Python search path, create an entry for it in your configuration file,
16 this::
16 like this::
17
17
18 [extensions]
18 [extensions]
19 foo =
19 foo =
20
20
21 You may also specify the full path to an extension::
21 You may also specify the full path to an extension::
22
22
23 [extensions]
23 [extensions]
24 myfeature = ~/.hgext/myfeature.py
24 myfeature = ~/.hgext/myfeature.py
25
25
26 To explicitly disable an extension enabled in an hgrc of broader
26 To explicitly disable an extension enabled in a configuration file of
27 scope, prepend its path with !::
27 broader scope, prepend its path with !::
28
28
29 [extensions]
29 [extensions]
30 # disabling extension bar residing in /path/to/extension/bar.py
30 # disabling extension bar residing in /path/to/extension/bar.py
31 bar = !/path/to/extension/bar.py
31 bar = !/path/to/extension/bar.py
32 # ditto, but no path was supplied for extension baz
32 # ditto, but no path was supplied for extension baz
33 baz = !
33 baz = !
@@ -1,63 +1,63 b''
1 Valid URLs are of the form::
1 Valid URLs are of the form::
2
2
3 local/filesystem/path[#revision]
3 local/filesystem/path[#revision]
4 file://local/filesystem/path[#revision]
4 file://local/filesystem/path[#revision]
5 http://[user[:pass]@]host[:port]/[path][#revision]
5 http://[user[:pass]@]host[:port]/[path][#revision]
6 https://[user[:pass]@]host[:port]/[path][#revision]
6 https://[user[:pass]@]host[:port]/[path][#revision]
7 ssh://[user[:pass]@]host[:port]/[path][#revision]
7 ssh://[user[:pass]@]host[:port]/[path][#revision]
8
8
9 Paths in the local filesystem can either point to Mercurial
9 Paths in the local filesystem can either point to Mercurial
10 repositories or to bundle files (as created by :hg:`bundle` or :hg:`
10 repositories or to bundle files (as created by :hg:`bundle` or :hg:`
11 incoming --bundle`).
11 incoming --bundle`).
12
12
13 An optional identifier after # indicates a particular branch, tag, or
13 An optional identifier after # indicates a particular branch, tag, or
14 changeset to use from the remote repository. See also :hg:`help
14 changeset to use from the remote repository. See also :hg:`help
15 revisions`.
15 revisions`.
16
16
17 Some features, such as pushing to http:// and https:// URLs are only
17 Some features, such as pushing to http:// and https:// URLs are only
18 possible if the feature is explicitly enabled on the remote Mercurial
18 possible if the feature is explicitly enabled on the remote Mercurial
19 server.
19 server.
20
20
21 Some notes about using SSH with Mercurial:
21 Some notes about using SSH with Mercurial:
22
22
23 - SSH requires an accessible shell account on the destination machine
23 - SSH requires an accessible shell account on the destination machine
24 and a copy of hg in the remote path or specified with as remotecmd.
24 and a copy of hg in the remote path or specified with as remotecmd.
25 - path is relative to the remote user's home directory by default. Use
25 - path is relative to the remote user's home directory by default. Use
26 an extra slash at the start of a path to specify an absolute path::
26 an extra slash at the start of a path to specify an absolute path::
27
27
28 ssh://example.com//tmp/repository
28 ssh://example.com//tmp/repository
29
29
30 - Mercurial doesn't use its own compression via SSH; the right thing
30 - Mercurial doesn't use its own compression via SSH; the right thing
31 to do is to configure it in your ~/.ssh/config, e.g.::
31 to do is to configure it in your ~/.ssh/config, e.g.::
32
32
33 Host *.mylocalnetwork.example.com
33 Host *.mylocalnetwork.example.com
34 Compression no
34 Compression no
35 Host *
35 Host *
36 Compression yes
36 Compression yes
37
37
38 Alternatively specify "ssh -C" as your ssh command in your hgrc or
38 Alternatively specify "ssh -C" as your ssh command in your
39 with the --ssh command line option.
39 configuration file or with the --ssh command line option.
40
40
41 These URLs can all be stored in your hgrc with path aliases under the
41 These URLs can all be stored in your configuration file with path
42 [paths] section like so::
42 aliases under the [paths] section like so::
43
43
44 [paths]
44 [paths]
45 alias1 = URL1
45 alias1 = URL1
46 alias2 = URL2
46 alias2 = URL2
47 ...
47 ...
48
48
49 You can then use the alias for any command that uses a URL (for
49 You can then use the alias for any command that uses a URL (for
50 example :hg:`pull alias1` will be treated as :hg:`pull URL1`).
50 example :hg:`pull alias1` will be treated as :hg:`pull URL1`).
51
51
52 Two path aliases are special because they are used as defaults when
52 Two path aliases are special because they are used as defaults when
53 you do not provide the URL to a command:
53 you do not provide the URL to a command:
54
54
55 default:
55 default:
56 When you create a repository with hg clone, the clone command saves
56 When you create a repository with hg clone, the clone command saves
57 the location of the source repository as the new repository's
57 the location of the source repository as the new repository's
58 'default' path. This is then used when you omit path from push- and
58 'default' path. This is then used when you omit path from push- and
59 pull-like commands (including incoming and outgoing).
59 pull-like commands (including incoming and outgoing).
60
60
61 default-push:
61 default-push:
62 The push command will look for a path named 'default-push', and
62 The push command will look for a path named 'default-push', and
63 prefer it over 'default' if both are defined.
63 prefer it over 'default' if both are defined.
@@ -1,23 +1,23 b''
1 hg debuginstall
1 hg debuginstall
2 $ hg debuginstall
2 $ hg debuginstall
3 Checking encoding (ascii)...
3 Checking encoding (ascii)...
4 Checking installed modules \(.*/mercurial\)...
4 Checking installed modules \(.*/mercurial\)...
5 Checking templates...
5 Checking templates...
6 Checking patch...
6 Checking patch...
7 Checking commit editor...
7 Checking commit editor...
8 Checking username...
8 Checking username...
9 No problems detected
9 No problems detected
10
10
11 hg debuginstall with no username
11 hg debuginstall with no username
12 $ HGUSER= hg debuginstall
12 $ HGUSER= hg debuginstall
13 Checking encoding (ascii)...
13 Checking encoding (ascii)...
14 Checking installed modules \(.*/mercurial\)...
14 Checking installed modules \(.*/mercurial\)...
15 Checking templates...
15 Checking templates...
16 Checking patch...
16 Checking patch...
17 Checking commit editor...
17 Checking commit editor...
18 Checking username...
18 Checking username...
19 no username supplied (see "hg help config")
19 no username supplied (see "hg help config")
20 (specify a username in your .hgrc file)
20 (specify a username in your configuration file)
21 1 problems detected, please check your install!
21 1 problems detected, please check your install!
22
22
23 $ true
23 $ true
General Comments 0
You need to be logged in to leave comments. Login now