Before this patch, "hg qselect" with --pop/--reapply may pop patches
unexpectedly, even when all of patches applied before "qselect" are
still pushable.
Strictly speaking about the condition of this issue:
- before "qselect"
- there are N applied patches
- the index of the guarded patch X in the series is less than N
- after "qselect"
- X is still guarded, and
- all of applied patched are still pushable
In the case above, "hg qselect" should keep current status, but it
actually tries to pop patches because of X.
The index in "the series" should be used to examine "pushable" of a
patch by "mq.pushablek()", but the index in "applied patches" is used,
and this may cause unexpected examination of guarded patch.
To examine "pushable" of already applied patch correctly, this patch
uses "mq.applied[i].name": "pushable" is the function introduced by
the previous patch, and it returns "mq.pushable(mq.applied[i].name)[0]".
Before this patch, "hg qselect" with --pop/--reapply may pop incorrect
patches, because the index in "applied patches" is used to pop patches
by "mq.pop()", even though the index in "the series" should be used.
For example, when the already applied patch becomes guarded and it
follows the already guarded (= not yet applied) one, "hg qselect" is
aborted, because it tries to pop to guarded one.
This patch uses "mq.applied[i - 1].name" to pop to the patch, of which
the index in the "applied ones" is "i - 1".
Before this patch, "hg qselect --reapply" is aborted when "--verbose"
is specified, because "mq.appliedname()" returns "INDEX PATCHNAME"
instead of "PATCHNAME" in such case and "mq.push" can't accept the
former as the name of patch.
This patch uses "mq.applied[i].name" instead of "mq.appliedname(i)" as
the name of the patch to be pushed for safety.
Now, there is no code path using "mq.appliedname()", and it should be
removed to prevent developers from using it in the wrong way like this
issue.
Before this patch, "hg qselect" may report incorrect numbers for
"number of guarded, applied patches has changed", because it examines
"pushable" of patches by the index not in "the series" but in "applied
patches", even though "mq.pushable()" expects the former.
To report correct numbers for changing "number of guarded, applied
patches", this patch uses the name of applied patch to examine
pushable-ness of it.
This patch also changes the result of existing "hg qselect" tests,
because they doesn't change pushable-ness of already applied patches.
This patch assumes that "hg qselect" focuses on changing pushable-ness
only of already applied patches, because:
- the report message uses not "previous" (in the series) but
"applied"
- the logic to pop patches for --pop/--reapply examines
pushable-ness only of already applied ones (in fact, there are
some incorrect code paths)
This patch changes help text for "--edit" option of commands below:
- fetch
- qnew
- qrefresh
- qfold
- commit
- tag
This unification reduces translation cost, too.
This patch chooses not "further edit commit message already specified"
(of "hg commit") but "invoke editor on commit messages" as unified
help text for "--edit" option, because the latter is much older than
the former.
This wraps all the locations of dirstate.setparent with the appropriate
begin/endparentchange calls. This will prevent exceptions during those calls
from causing incoherent dirstates (issue4353).
We now pass a transaction option to this phase movement function. The
object is currently not used by the function, but it will be in the
future.
All call sites have been updated. Most call sites were already enclosed in a
transaction for a long time. The handful of others have been recently
updated in previous commit.
We now pass a transaction option to this phase movement function. The object
is currently not used by the function, but it will be in the future.
All call sites have been updated. Most call sites were already enclosed in a
transaction for a long time. The handful of others have been recently
updated in previous commit.
The retractboundary function remains to be upgraded.
cset 21b4faf3787e has removed this option. This commit just tidies the
code that was associated to it. It also fixes the internal calls to
the strip() function.
Before this change, any function that thought it would want as a final
safety to keep a partial backup bundle (bundling changes not linearly
related to the current change being stripped), had to explicitly pass
a backup="strip" option. With this change, these backups are always
kept in case of an exception and always removed if there is no
exception. Only full backups can be specified with backup=True or no
full backups with backup=False.
This patch passes 'editform' argument according to the format below:
EXTENSION[.COMMAND][.ROUTE]
- EXTENSION: name of extension
- COMMAND: name of command, if there are two or more commands in EXTENSION
- ROUTE: name of route, if there are two or more routes in COMMAND
In this patch:
- MQ command names (qnew/qrefresh/qfold) are used as COMMAND
- ROUTE is omitted
Before this patch, 'hg qfold' disallows to specify
'--message/'--logfile' and '--edit' at the same time.
'hg qfold' has disallowed such combination since Mercurial 0.9.2, but
this restriction seems not to be reasonable for recent Mercurial,
because all other commands creating new changeset allow it.
This patch allows 'hg qfold' to specify '--message/'--logfile' and
'--edit' at the same time like other commands creating new changeset.
Before this patch, 'hg qrefresh' disallows to specify
'--message/'--logfile' and '--edit' at the same time.
'hg qrefresh' has disallowed such combination since Mercurial 0.9.2,
but this restriction seems not to be reasonable for recent Mercurial,
because all other commands creating new changeset allow it.
This patch allows 'hg qrefresh' to specify '--message/'--logfile' and
'--edit' at the same time like other commands creating new changeset.
This patch also replaces "editor = False" by "editor =
cmdutil.getcommiteditor()", because:
- it allows to hook commit message determination easily, even in the
case without "--edit"
- it avoids regression (or additional care) around saving
"last-message.txt", even if MQ's "newcommit()" changes its
implementation logic from "localrepository.commit" to
"localrepository.commitctx" with "memctx" in the future
to save commit message into "last-messge.txt" with "memctx",
"editor" should be valid function.
This patch also replaces "editor = False" by "editor =
cmdutil.getcommiteditor()", because:
- the latter allows to hook commit message determination easily,
even in the case without "--edit"
- the latter can avoid regression (or additional care) around saving
"last-message.txt", even if MQ's "newcommit()" changes its
implementation logic from "localrepository.commit" to
"localrepository.commitctx" with "memctx" in the future
to save commit message into "last-messge.txt" with "memctx",
"editor" should be valid function.
Before this patch, "hg qrefresh" and "hg qfold" invoke "ui.edit()"
explicitly to get commit message edited manually.
This requires explicit "localrepository.savecommitmessage()"
invocation to save edited commit message into ".hg/last-message.txt",
because unexpected exception raising may abort command execution
before saving it in "localrepository.commit()".
This patch uses "editor" argument of "localrepository.commit()"
instead of explicit "ui.edit()" invocation for "hg qnew" and "hg qfold"
"localrepository.commit()" will invoke "desceditor()" function newly
added by this patch, and save edited commit message into
".hg/last-message.txt" automatically.
This patch passes not "editor" but "desceditor" to "commit()", because
"hg qnew" and "hg qfold" require editor function to return edited
message (and invoke "patchheader.setmessage()" with it) if not empty,
or default message otherwise.
This patch also avoids "not q.applied" check at "hg qrefresh --edit",
because it is also checked in "queue.refresh()", and it is not needed
to get commit message from patch header before "queue.refresh()".
Before this patch, commit message for refreshed MQ changeset is
determined, and written into refreshed patch file before
"localrepository.commit()" invocation.
This makes refactoring to use "editor" argument of "commit()" instead
of explicit "ui.edit()" invocation in succeeding patch difficult.
This patch relocates message/patch-header handling to delay message
determination.
Before this patch, "hg qnew" invokes "ui.edit()" explicitly to get
commit message edited manually.
This requires explicit "localrepository.savecommitmessage()"
invocation to save edited commit message into ".hg/last-message.txt",
because unexpected exception raising may abort command execution
before saving it in "localrepository.commit()".
This patch uses "editor" argument of "localrepository.commit()"
instead of explicit "ui.edit()" invocation for "hg qnew".
"localrepository.commit()" will invoke "desceditor()" function newly
added by this patch, and save edited commit message into
".hg/last-message.txt" automatically.
This patch passes not "editor" but "desceditor" to "commit()", because
"hg qnew" requires editor function to return edited message if not
empty, or default message otherwise.
This patch applies "rstrip()" on "defaultmsg" at comparison between
"nctx.description()" and "defaultmsg", because the former should be
stripped by "changelog.stripdesc()" and the latter may have tail white
spaces inherited from "patchfn".
The `pushoperation` object contains strictly more data the arguments currently
passed to `localrepo.checkpush` we pass the new object instead. This function is
used by MQ to abort push that includes MQ changesets.
Note: extension that may use this function will have to align.
Before this patch, "localrepository.commit()" omits ".hgsubstate" from
"modified" (changes[0]) and "removed" (changes[2]) file list before
checking subrepositories, but leaves one in "added" (changes[1]) as it
is.
Then, "localrepository.commit()" adds ".hgsubstate" into "modified" or
"removed" list forcibly, according to subrepository statuses.
If "added" contains ".hgsubstate", the committed context will contain
two ".hgsubstate" in its "files": one from "added" (not omitted one),
and another from "modified" or "removed" (newly added one).
How many times ".hgsubstate" appears in "files" changes node hash,
even though revision content is same, because node hash calculation
uses the specified "files" directly (without duplication check or so).
This means that node hash of committed revision changes according to
existence of ".hgsubstate" in "added" at "localrepository.commit()".
".hgsubstate" is treated as "added", not only in accidental cases, but
also in the case of "qpush" for the patch adding ".hgsubstate".
This patch omits ".hgsubstate" also from "added" files before checking
subrepositories. This patch also omits ".hgsubstate" exclusion in
"qnew"/"qrefresh" introduced by changeset bbb8109a634f, because this
patch makes them meaningless.
"hg parents --template '{files}\n'" newly added to "test-mq-subrepo.t"
enhances checking unexpected multiple appearances of ".hgsubstate" in
"files" of created/refreshed MQ revisions.
Some extensions set configuration settings that showed up in 'hg showconfig
--debug' with 'none' as source. That was confusing.
Instead, they will now tell which extension they come from.
This change tries to be consistent and specify a source everywhere - also where
it perhaps is less relevant.
Before this patch, even if specified file patterns and -I/-X options
cause listing ".hgsubstate" up in the target list, qnew/qrefresh put
".hgsubstate" into the target list individually and forcibly.
This changes how many times ".hgsubstate" appear in the target list
according to run-time conditions, and causes inconsistent node hash,
even though revision content is same, because node hash calculation
uses the specified target list directly (without duplication check or
so).
This patch always omits ".hgsubstate" from qnew/qrefresh target list
for consistent node hash.
This omitting doesn't miss including ".hgsubstate" changes, because:
- "localrepository.commit()" puts ".hgsubstate" into the target list
for "commitctx()" forcibly if needed
- "mq.putsubstate2changes()" puts ".hgsubstate" into the target list
for "patch.diff()" if it is not yet listed up
Before this patch, qnew puts updated subrepositories into target list
forcibly, if any of -I, -X or patterns are specified.
But this is meaningless and harmful, because:
- putting subrepositories into target list doesn't affect the result
of "localrepository.status()"
"dirstate.status()" invoked via "localrepository.status()" always
omits subrepositories from the result of it
- any -I/-X opts and empty "pats" causes unexpected failure
when any -I/-X opts are specified, "inclsubs" are always added to
"pats", even if "pats" is empty.
but this changes meaning of "pats" from "including all to be
included" to "including only listed subrepositories"
this may exclude ".hgsub" and cause unexpected exception raising
("can't commit subrepos without .hgsub" ).
- qnew at other than repository root (with -I, -X or any patterns)
causes unexpected failure
"scmutil.match()" treats pattern without syntax type as 'relpath'
type (= one rooted at cwd).
but qnew puts subrepository paths rooted at the repository root,
and it causes unexpected exception raising ("SUBREPO not under
root ROOT" in "pathutil.canonpath()"), if "hg qnew" is executed at
other than repository root with -I, -X or any patterns.
This patch omits meaningless and harmful putting subrepositories into
target list.
This omitting doesn't miss including updated subrepositories, because
subrepositories are specified to "scmutil.matchfiles()" directly, to
get "match" object for "localrepository.commit()".
Before this patch, manually edited commit message for "hg qfold -e"
isn't saved into ".hg/last-message.txt" until it is saved by
"localrepository.savecommitmessage()" in "localrepository.commit()".
This may lose such commit message, if unexpected exception is raised.
This patch saves manually edited commit message for "hg qfold -e" into
".hg/last-message.txt" just after user editing. This patch doesn't
save the message specified by -m/-l options as same as other commands.
This is the simplest implementation to fix on stable. Editing and
saving commit message should be centralized into the framework of
"localrepository.commit()" with "editor" argument in the future.
This patch uses repository wrapping class for exception raising before
saving commit message in "localrepository.commit()" easily and
certainly, because such exception requires corner case condition.
Before this patch, manually edited commit message for "hg qnew -e"
isn't saved into ".hg/last-message.txt" until it is saved by
"localrepository.savecommitmessage()" in "localrepository.commit()".
This may lose such commit message, if unexpected exception is raised.
This patch saves manually edited commit message for "hg qnew -e" into
".hg/last-message.txt" just after user editing. This patch doesn't
save the message specified by -m/-l options as same as other commands.
This is the simplest implementation to fix on stable. Editing and
saving commit message should be centralized into the framework of
"localrepository.commit()" with "editor" argument in the future.
This patch uses repository wrapping class for exception raising before
saving commit message in "localrepository.commit()" easily and
certainly, because such exception requires corner case condition.
The [x for y in l for x in y] syntax is nigh-incomprehensible, and this
is a particularly easy case to expand into a loop since there's no 'if'
condition in the list comprehension.
We allow shelving of of changes on top of a MQ repository. MQ will
not allow repository changes on top of applied patches. We introduce
checkapplied in MQ to bypass this check.
Strip now lives in its own extension
reminder: The extension is surprisingly called `strip`. The `mq` extension
force the use of the strip extension when its enabled. This is both necessary
for backward compatibility (people expect `mq` to comes with strip) and become
some utility function used by `mq` are now in the strip extension.
Strip will lives in its own extension. The extension is surprisingly called
`strip`. (as discussed in issue3824) The `mq` extension force the use of the
strip extension when its enabled. This will both necessary for backward
compatibility (people expect `mq` to comes with strip) and become some utility
function used by `mq` will move in the strip extension.
This is the last step before being able to extract `strip` in its own extension.
The changes are made in mq to allow a move only extraction without touching a
line of code.
Same as in the previous changeset, rev is never `None`. We can just copy the two
relevant lines in in `queue.strip`. This help having `queue.strip` independent
from `queue`. One further step toward the extraction of `strip` in an independent
extension. (As discussed in issue3824).
In this case, rev is never `None`. We can just copy the two relevant lines in
in `strip`. This help having `strip` independent from `queue` one
further step toward its extraction in an independent extension. (As
discussed in issue3824).
The core part of `checklocalchanges` is now mq independent. We can extract it in
a standalone function to help the extraction of `strip` as discussed in issue3824.
A `checklocalchanges` function stay in `mq.queue` with the part related to
"refresh first" messages.
This function does not need any of the the `mq.queue` method or attributes. It
is indirectly used by the `strip` command. We are trying to extract this command
in a standalone extension as discussed in issue issue3824.
The `checklocalchanges` function in the `mq.queue` class takes a `refresh` argument that
changes the error message of raised exception. When refresh is
`True` the exception message is "local changes found, refresh first" otherwise,
the message is just "local changes found".
This changeset is the first of a series that extract `strip` into a standalone
extension (as discussed in issue3824). This `checklocalchanges` function is
indirectly used by the strip command. But in a standalone strip extension the
concept of "refresh first" has no sense. In practice, When used in the context
of the strip commands `refresh`'s value is always `False`.
So my final goal is a be able to extract the `checklocalchanges` logic in a
standalone extension but to keep the part related to "refresh first" in the mq
extension. However the refresh handling is deeply entangled into the
`checklocalchanges` code. It is handled as low a possible at the point we raise
the exception.
So we moves handling of refresh upper in the `checklocalchanges` code. This will
allow the extraction of a simple version in the strip extension while mq can
still inject its logic when needed.
Two helper functions `localchangesfound` and `localchangedsubreposfound` died in
the process they are replaced by simple raise lines.
Up until now applying or unapplying a patch that modified .hgsubstate would not
work as expected because it would not update the subrepos according to the
.hgsubstate change. This made it very easy to lose subrepo changes when using
mq.
This revision also changes the test-mq-subrepo test so that on the qpop / qpush
tests. We no longer use the debugsub command to check the state of the subrepos
after the qpop and qpush operations. Instead we directly run the id command on
the subrepos that we want to check. The reason is that using the debugsub
command is misleading because it does not really check the state of the subrepos
on the working directory (it just returns what the change that is specified on a
given revision). Because of this the tests did not detect the problem that this
revision fixes (i.e. that applying a patch did not update the subrepos to the
corresponding revisions).
# HG changeset patch
# User Angel Ezquerra <angel.ezquerra@gmail.com>
# Date 1376350710 -7200
# Tue Aug 13 01:38:30 2013 +0200
# Node ID 60897e264858cdcd46f89e27a702086f08adca02
# Parent 2defb5453f223c3027eb2f7788fbddd52bbb3352
mq: update subrepos when applying / unapplying patches that change .hgsubstate
Up until now applying or unapplying a patch that modified .hgsubstate would not
work as expected because it would not update the subrepos according to the
.hgsubstate change. This made it very easy to lose subrepo changes when using
mq.
This revision also changes the test-mq-subrepo test so that on the qpop / qpush
tests. We no longer use the debugsub command to check the state of the subrepos
after the qpop and qpush operations. Instead we directly run the id command on
the subrepos that we want to check. The reason is that using the debugsub
command is misleading because it does not really check the state of the subrepos
on the working directory (it just returns what the change that is specified on a
given revision). Because of this the tests did not detect the problem that this
revision fixes (i.e. that applying a patch did not update the subrepos to the
corresponding revisions).
It was possible to apply, unapply, fold, patches (etc) with modified subrepos,
which resulted in surprising behavior. For example it was easy to apply a patch
with a modified subrepo, and then the refresh it and accidentally end up
including the modified subrepo on the refreshed patch.
A test has been added to verify this new check.
# HG changeset patch
# User Angel Ezquerra <angel.ezquerra@gmail.com>
# Date 1375742979 -7200
# Tue Aug 06 00:49:39 2013 +0200
# Node ID a5c90acff5e61aae714ba6c9457d766c54b4f124
# Parent bacc55ce64d5de9d1eb7fcefccd3829161d5dcf7
mq: look for modified subrepos when checking for local changes
It was possible to apply, unapply, fold, patches (etc) with modified subrepos,
which resulted in surprising behavior. For example it was easy to apply a patch
with a modified subrepo, and then the refresh it and accidentally end up
including the modified subrepo on the refreshed patch.
A test has been added to verify this new check.
The same `queue` object should be used in all situations. This allows to store
global states on the object (like the reworked shelve extension plans to). The
queue object does not need to be distinct for all possible views (no reference
to the repo/view used at creation time) it's even a bit surprising that mq still
works with the current code.
hg strip -k was using dirstate.rebuild() which reset all the dirstate
entries timestamps to 0. This meant that the next time hg status was
run every file was considered to be 'unsure', which caused it to do
expensive read operations on every filelog. On a repo with >150,000
files it took 70 seconds when everything was in memory. From a cold
cache it took several minutes.
The fix is to only reset files that have changed between the working
context and the destination context.
For reference, --keep means the working directory is left alone during
the strip. We have users wanting to use this operation to store their
work-in-progress as a commit on a branch while they go work on another
branch, then come back later and be able to uncommit that work and
continue working. They currently use 'git reset HARD^' to accomplish
this in git.
mq was injecting fake tags whenever the revisions were accessible
to the filtering level.
This issue impacts hgweb since it's common to have "secret" mq
patches. As secret changesets are filtered by hgweb, the tags
computation could break.
Strip will (if it updates) update to the parent of revs[0], where revs are the
roots of the tree that is stripped.
When revs was list(set) it was thus undefined which root parent it would update
to. With sorted(set) it is at least stable what it updates to. (But it is very
possible that another more useful and predictable behaviour could be defined
... such as updating to the tip-most surviving wd ancestor.)
Add sorted() in places found by testing with PYTHONHASHSEED=random and code
inspection.
An alternative to sprinkling sorted() all over would be to change substate to a
custom dict with sorted iterators...
mq assumed that it had to update from qtip to qparent, and instead of updating
from where it was it failed with:
abort: working directory revision is not qtip
Strip have dedicated work around to solve the same problem, strip is even a
fraction faster without that thanks to simpler update process of the branchcache.
The current _branchtags method is a remnant of an older, much larger function.
Its only remaining role is to help MQ to alter the version of branchcache we
store on disk. As MQ mutates the repository it ensures persistent cache does not
contain anything it is likely to alter.
This changeset makes explicit the stable vs volatile part of repository and
reduces the MQ specific code to the computation of this limit. The main
_branchtags code now handles this possible limit in all cases.
This will help to extract the branchmap logic from the repository.
The new code of _branchtags is a bit duplicated, but as I expect major
refactoring of this section I'm not keen to setup factorisation function here.
The check pattern only checked for whitespace between keyword and operator.
Now it also warns:
> x = f(),7
missing whitespace after ,
> x = f()+7
missing whitespace in expression
MQ warns when qstatus contains unknown nodes. With changelog filtering,
a node may be unknown because it is filtered. Thus, an unfiltered repo
is used for this check.
Bookmarks persistence still showed a fair amount of its legacy as a
monkeypatching extension. This encapsulates all bookmarks
serialization and parsing in a single class, and offers a single
location where other bookmarks storage engines can be substituted
in. As a result, many files no longer import the bookmarks module,
which strikes me as an encapsulation win.
This doesn't do anything to the current bookmark state yet, but I'm
hoping put that in the bmstore class as well.
Before this patch, one of column positioning messages of MQ summary
output is not translatable, and patches are always listed up at fixed
column position like below, when patch queue is not empty:
mq: 1 applied, 1 unapplied
But column positioning messages for other summarized information are
translatable, so other information may be displayed at different
column position on non-English locale environments.
This patch makes column positioning message of MQ summary output
translatable.
When calling qrefresh with filenames, the filenames were being
treated as case-sensistive on case-insensitive file systems.
So 'qrefresh foo' would not match file 'Foo', and it failed silently.
This fix makes it work correctly on case-insensitive file systems.
Previously the matching function was applied directly to the filenames.
Now we apply the matching function through repo.status, which handles
the case logic for us. A side effect of using repo.status is that
if the qrefresh file doesn't exist, there is output stating it
doesn't exist.
Adds a test to an existing mq refresh case test.
Maintain a whitelist of commands to infer the repo for instead. The whitelist
contains those commands that take file(s) in the working dir as arguments.
Bookmarks are updated during qpop and qpush, but they are not updated
during qrefresh. This behaviour makes it hard to work on an evolving
changeset at the head of a branch. qrefresh should update all bookmarks
that point to the refreshed commit with the new nodeid.
This introduces a peer method into all repository classes, which currently
simply returns self. It also changes hg.repository so it now raises an
exception if the supplied paths does not resolve to a localrepo or descendant.
Finally, all call sites are changed to use the peer and local methods as
appropriate, where peer is used whenever the code is dealing with a remote
repository (even if it's on local disk).
Before this patch, MQ checks each subrepo synchronizations against the
working directory context, so ".hgsubstate" updating is not imported
into MQ revision correctly in cases below:
- qrefresh when current ".hgsubstate" is already synchronized with
each subrepos: you can reproduce this easily by just twice or more
qrefresh invocations
- qnew just after rollback of commit which updates ".hgsubstate"
This patch resolves this by checking subrepo states against:
- the parent of "qtop" for qrefresh, or
- the parent of working context otherwise
Even though the committed revision contains diff of ".hgsubstate", the
patch file created by qrefresh doesn't contain it, because:
- ".hgsubstate" is not listed up as one of target files of the patch
for reasons below, so diff of ".hgsubstate" is not imported into
patch file
- status of ".hgsubstate" in working directory is usually "clean"
- ".hgsubstate" is not specified explicitly by users
- the patch file is created before commit processing which updates
or creates ".hgsubstate" automatically, so there is no diff for it
at that time
This patch resolves this problem by:
- putting ".hgsubstate" into target list of the patch, if needed:
this allows "patch.diff()" to import diff of ".hgsubstate" into
patch file.
- creating the patch file after commit processing:
this updates ".hgsubstate" before "patch.diff()" invocation.
For the former fixing, this patch introduces "putsubstate2changes()"
to share same implementation with qnew. This is invoked only once per
qnew/qrefresh at most, so there is less performance impact.
This patch also omits "match" argument for "patch.diff()" invocation,
because "patch.diff()" ignores "match" if "changes" is specified.
If ".hgsubstate" is already listed up as one of commit targets, qnew
put diff of ".hgsubstate" twice into the patch file stored under
".hg/patches".
It causes rejections at applying such patches.
Other than the case like in added test script, this can also occur
when qnew is executed just after rolling back the committing updated
".hgsubstate".
This patch checks whether ".hgsubstate" is already listed up as one of
commit targets, and put it into the appropriate list only if it is not
listed up yet.
mq wraps all commands that are not in commands.norepo, which is now performed in
this second phase of the extensions setup process. This goes against the
current best practices on the wiki [1] as far as where command wrapping is
performed, but follows it regarding where global options are injected.
mq needs to be the first layer called when command dispatching in order to
consistently retarget to the patch repo, regardless of the load order of the
extensions. This means being the last to wrap the command table. Previously,
'hg <extdiff> --mq' would diff the main repo unless mq was enabled after
extdiff.
[1] http://mercurial.selenic.com/wiki/WritingExtensions
I named it --check because it felt like qpush & co were checking *more*
things to ensure local changes could not be lost. But it has been
pointed on the mailing list that --check is already used by update
command with a meaning almost opposite to this one. An alternative
was --keep but qfold and qdelete already have such an option to preserve
patch files and qfold may be a candidate for --check.
- qpush/qpop/qgoto --check becomes --keep-changes.
- mq.check becomes mq.keepchanges.
- The short option -c is dropped as -k may conflict with existing
--keep. The availabilitity of mq.keepchanges should not make this too
painful.
- Fix minor reST mistake in option description.
Add a -B option to remove a bookmark. All revisions are unreachable
from a different head or a different bookmark will be removed too.
This helps with topic branch workflow. You can create a topic branch
and remove it if not needed anymore with hg strip -B topic/xyz.
The original motivation was changectx.phase() had special logic to
correctly lookup in repo._phaserev, including invalidating it when
necessary. And at other places, repo._phaserev was accessed directly.
This led to the discovery that phases state including _phaseroots,
_phaserev and _dirtyphase was manipulated in localrepository.py,
phases.py, repair.py, etc. phasecache helps encapsulating that.
This patch replaces all phase state in localrepo with phasecache and
adjust related code except for advance/retractboundary() in phases.
These still access to phasecache internals directly. This will be
addressed in a followup.
When:
[mq]
check = True
is set, qpush, qpop and qgoto behave as if -c/--check were passed. If
incompatible options like -f/--force or --exact are set, this setting is
ignored.
This setting enables what many users expect mq default behaviour to be.
qpush help says the following about --force:
1- When -f/--force is applied, all local changes in patched files will
be lost.
2- Apply on top of local changes
In practice, qpush --force will attempt to apply the patch on top of
local changes, and on success will merge them in the pushed patch. On
failure, patched files will contain a mix of local changes (where the
patch could not apply) and a mix of patch changes (were it applied). So,
local changes are less lost than entangled with a mass of other changes.
This patch makes qpush --force backup all locally modified files touched
by the next patch being applied. When multiple patches are being pushed,
this logic is repeated for each patch. Note that modified but
successfully patched files are preserved as well.
The fix introduced in 3509b9cf8f86 was only partially successful. It is correct
to turn dirstate 'm' merge records into normal/dirty ones but copy records are
lost in the process. To adjust them as well, we need to look in the first
parent manifest to know which files were added and preserve only related
records. But the dirstate does not have access to changesets, the logic has to
moved at another level, in localrepo.
'hg qnew' passes matching object to 'patch.diff()' to specify target
filenames, and it causes 'dirstate.walk()' via 'repo.status()' in
'patch.diff()'.
but target files are already known before 'patch.diff()' invocation.
to avoid useless 'dirstate.walk()' invocation, this patch uses
'changes' argument to pass already known target files to
'patch.diff()' instead of 'match' argument.
'changes' argument of 'patch.diff()' should have lists for modified,
added and removed files separately, so this patch saves status of
'.hgsubstate' before commit, and put it into appropriate list in
'changes'.
'hg qnew' with pattern/-I/-X creates matching object with them, and
uses it twice for 'dirstate.walk()': via 'repo.status()' and
'repo.commit()'.
this may cause full manifest scan in the second 'dirstate.walk()',
even though mq already knows complete target filenames at the first
'dirstate.walk()'.
this patch creates exact matching object also in this case, and use it
at 'repo.commit()' invocation to avoid full manifest scan in the
second 'dirstate.walk()'.
even though 'inclsubs' is added to 'pats' for original matching
object, it is also passed to exact matching object, because
subrepositories are deleted from result of 'dirstate.walk()' at the
end of it.
The 'start' variable pointed to qtip in self.series, but it was used for
indexing self.fullseries.
When fullseries had holes and the patch was moved to self.fullseries[start]
it would end up too early in self.series and it could thus not be
found in self.series[start:] and it would crash.
Now the 'fullstart' index in fullseries is found used instead.
In secret mode qfinished changeset were move to the draft phase in all case[1]
without regard to phases.new-commit value
This changeset ensure qfinish does not automatically promote a changeset
further than the phases.new-commit value.
Note: This may also result in qfinished changeset made public if
phases.new-commit is set to public.
[1] "In all case" where parent have a compatible phase. Qfinish keep never
altering phases of changeset not involved in the qfinish.
-n could be confused for --dry-run by foolhardy users, resulting in
permanent data loss.
As leaving a backup when none was requested is significantly less
disastrous, the short option is silently ignored. Old scripts continue
to work, users only get lightly burned.
Originally, mq.strip called repair.strip a single rev at a time.
repair.strip stores in a backup bundle any revision greater than
the revision being stripped, strips, then restores the backup with
repo.addchangegroup. So, when stripping revisions on more than one
topological branch, some could end up being restored from the backup
bundle, only to be later removed by a subsequent repair.strip call.
But repo.addchangegroup calls hooks for all those restore operations.
And 1671d21e8e41 changed it to delay all hook calls until the
repository lock were released - by mq.strip, after stripping all
revisions. Thus, the hooks could be called over revisions already
removed from the repository at that point.
By generating the revision lists at once inside repo.strip, we avoid
calling addchangegroup for temporary restores. Incidentally, this
also avoids creating many backup files for a single strip command.
Since c06eb45e85a7, mq saves the nodeid of the first applied patch to
cache/branchheads, which breaks the optimized cache handling introduced in
1808e27e1362. The problem is the revision being committed is appended to
mqrepo.applied after the commit succeeds, which means mqrepo._branchtags()
performs a regular update and write the first applied patch to the branch
cache.
One solution is to set a context variable _committingpatch on the mqrepo while
it is committing a patch and to take it in account when deciding to fast-path
mqrepo._branchtags(). Not really elegant but it works.
The changes to test-mq-caches.t reverse changes introduced by c06eb45e85a7. The
cache should not have been updated with mq records.
The changes to test-keyword.t are indirectly caused by c06eb45e85a7.
Reported and analyzed by Yuya Nishihara <yuya@tcha.org>
Notes:
- qpush still makes a slow path _branchtags() call when checking heads. Maybe
this can be optimized.
- be careful when merging this patch in default as secretcommit() was renamed
newcommit() right after the end of the code freeze.
The current behaviour is to return the previous one in the series but at the
same time the implementation is buggy because it does not take guarded patches
in account.