Mercurial > public > mercurial-scm > hg
comparison mercurial/commands.py @ 16458:55982f62651f
commit: add option to amend the working dir parent
The --amend flag can be used to amend the parent of the working directory
with a new commit that contains the changes in the parent in addition to
those currently reported by "hg status", if there are any. The old commit
is stored in a backup bundle in ".hg/strip-backup"(see "hg help bundle"
and "hg help unbundle" on how to restore it).
Message, user and date are taken from the amended commit unless specified.
When a message isn't specified on the command line, the editor will open
with the message of the amended commit.
It is not possible to amend public changesets (see "hg help phases") or
changesets that have children.
Behind the scenes, first commit the update (if there is one) as a regular
child of the current parent. Then create a new commit on the parent's
parent with the updated contents. Then change the working copy parent
to this new combined changeset. Finally, strip the amended commit and
update commit created in the beginning.
An alternative (cleaner?) approach of doing this is suggested here:
http://selenic.com/pipermail/mercurial-devel/2012-March/038540.html
It is currently not possible to amend merge commits or recursively,
this can be added at a later time.
author | Idan Kamara <idankk86@gmail.com> |
---|---|
date | Wed, 18 Apr 2012 01:20:16 +0300 |
parents | d54d4de56aa7 |
children | b2e1da5db6df |
comparison
equal
deleted
inserted
replaced
16457:91196ebcaeed | 16458:55982f62651f |
---|---|
1161 @command('^commit|ci', | 1161 @command('^commit|ci', |
1162 [('A', 'addremove', None, | 1162 [('A', 'addremove', None, |
1163 _('mark new/missing files as added/removed before committing')), | 1163 _('mark new/missing files as added/removed before committing')), |
1164 ('', 'close-branch', None, | 1164 ('', 'close-branch', None, |
1165 _('mark a branch as closed, hiding it from the branch list')), | 1165 _('mark a branch as closed, hiding it from the branch list')), |
1166 ('', 'amend', None, _('amend the parent of the working dir')), | |
1166 ] + walkopts + commitopts + commitopts2 + subrepoopts, | 1167 ] + walkopts + commitopts + commitopts2 + subrepoopts, |
1167 _('[OPTION]... [FILE]...')) | 1168 _('[OPTION]... [FILE]...')) |
1168 def commit(ui, repo, *pats, **opts): | 1169 def commit(ui, repo, *pats, **opts): |
1169 """commit the specified files or all outstanding changes | 1170 """commit the specified files or all outstanding changes |
1170 | 1171 |
1180 | 1181 |
1181 If no commit message is specified, Mercurial starts your | 1182 If no commit message is specified, Mercurial starts your |
1182 configured editor where you can enter a message. In case your | 1183 configured editor where you can enter a message. In case your |
1183 commit fails, you will find a backup of your message in | 1184 commit fails, you will find a backup of your message in |
1184 ``.hg/last-message.txt``. | 1185 ``.hg/last-message.txt``. |
1186 | |
1187 The --amend flag can be used to amend the parent of the | |
1188 working directory with a new commit that contains the changes | |
1189 in the parent in addition to those currently reported by :hg:`status`, | |
1190 if there are any. The old commit is stored in a backup bundle in | |
1191 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle` | |
1192 on how to restore it). | |
1193 | |
1194 Message, user and date are taken from the amended commit unless | |
1195 specified. When a message isn't specified on the command line, | |
1196 the editor will open with the message of the amended commit. | |
1197 | |
1198 It is not possible to amend public changesets (see :hg:`help phases`) | |
1199 or changesets that have children. | |
1185 | 1200 |
1186 See :hg:`help dates` for a list of formats valid for -d/--date. | 1201 See :hg:`help dates` for a list of formats valid for -d/--date. |
1187 | 1202 |
1188 Returns 0 on success, 1 if nothing changed. | 1203 Returns 0 on success, 1 if nothing changed. |
1189 """ | 1204 """ |
1196 if repo['.'].node() not in repo.branchheads(): | 1211 if repo['.'].node() not in repo.branchheads(): |
1197 # The topo heads set is included in the branch heads set of the | 1212 # The topo heads set is included in the branch heads set of the |
1198 # current branch, so it's sufficient to test branchheads | 1213 # current branch, so it's sufficient to test branchheads |
1199 raise util.Abort(_('can only close branch heads')) | 1214 raise util.Abort(_('can only close branch heads')) |
1200 extra['close'] = 1 | 1215 extra['close'] = 1 |
1201 e = cmdutil.commiteditor | |
1202 if opts.get('force_editor'): | |
1203 e = cmdutil.commitforceeditor | |
1204 | |
1205 def commitfunc(ui, repo, message, match, opts): | |
1206 return repo.commit(message, opts.get('user'), opts.get('date'), match, | |
1207 editor=e, extra=extra) | |
1208 | 1216 |
1209 branch = repo[None].branch() | 1217 branch = repo[None].branch() |
1210 bheads = repo.branchheads(branch) | 1218 bheads = repo.branchheads(branch) |
1211 | 1219 |
1212 node = cmdutil.commit(ui, repo, commitfunc, pats, opts) | 1220 if opts.get('amend'): |
1213 if not node: | 1221 if ui.config('ui', 'commitsubrepos'): |
1214 stat = repo.status(match=scmutil.match(repo[None], pats, opts)) | 1222 raise util.Abort(_('cannot amend recursively')) |
1215 if stat[3]: | 1223 |
1216 ui.status(_("nothing changed (%d missing files, see 'hg status')\n") | 1224 old = repo['.'] |
1217 % len(stat[3])) | 1225 if old.phase() == phases.public: |
1218 else: | 1226 raise util.Abort(_('cannot amend public changesets')) |
1227 if len(old.parents()) > 1: | |
1228 raise util.Abort(_('cannot amend merge changesets')) | |
1229 if len(repo[None].parents()) > 1: | |
1230 raise util.Abort(_('cannot amend while merging')) | |
1231 if old.children(): | |
1232 raise util.Abort(_('cannot amend changeset with children')) | |
1233 | |
1234 e = cmdutil.commiteditor | |
1235 if opts.get('force_editor'): | |
1236 e = cmdutil.commitforceeditor | |
1237 | |
1238 def commitfunc(ui, repo, message, match, opts): | |
1239 editor = e | |
1240 # message contains text from -m or -l, if it's empty, | |
1241 # open the editor with the old message | |
1242 if not message: | |
1243 message = old.description() | |
1244 editor = cmdutil.commitforceeditor | |
1245 return repo.commit(message, | |
1246 opts.get('user') or old.user(), | |
1247 opts.get('date') or old.date(), | |
1248 match, | |
1249 editor=editor, | |
1250 extra=extra) | |
1251 | |
1252 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts) | |
1253 if node == old.node(): | |
1219 ui.status(_("nothing changed\n")) | 1254 ui.status(_("nothing changed\n")) |
1220 return 1 | 1255 return 1 |
1256 else: | |
1257 e = cmdutil.commiteditor | |
1258 if opts.get('force_editor'): | |
1259 e = cmdutil.commitforceeditor | |
1260 | |
1261 def commitfunc(ui, repo, message, match, opts): | |
1262 return repo.commit(message, opts.get('user'), opts.get('date'), | |
1263 match, editor=e, extra=extra) | |
1264 | |
1265 node = cmdutil.commit(ui, repo, commitfunc, pats, opts) | |
1266 | |
1267 if not node: | |
1268 stat = repo.status(match=scmutil.match(repo[None], pats, opts)) | |
1269 if stat[3]: | |
1270 ui.status(_("nothing changed (%d missing files, see " | |
1271 "'hg status')\n") % len(stat[3])) | |
1272 else: | |
1273 ui.status(_("nothing changed\n")) | |
1274 return 1 | |
1221 | 1275 |
1222 ctx = repo[node] | 1276 ctx = repo[node] |
1223 parents = ctx.parents() | 1277 parents = ctx.parents() |
1224 | 1278 |
1225 if (bheads and node not in bheads and not | 1279 if (not opts.get('amend') and bheads and node not in bheads and not |
1226 [x for x in parents if x.node() in bheads and x.branch() == branch]): | 1280 [x for x in parents if x.node() in bheads and x.branch() == branch]): |
1227 ui.status(_('created new head\n')) | 1281 ui.status(_('created new head\n')) |
1228 # The message is not printed for initial roots. For the other | 1282 # The message is not printed for initial roots. For the other |
1229 # changesets, it is printed in the following situations: | 1283 # changesets, it is printed in the following situations: |
1230 # | 1284 # |