Mercurial: when did this changeset take effect in the stable-branch? - mercurial

Scenario: a colleague told me that a bug-fix I made was not in the current build. I said: "but I pushed it 2 weeks ago!"
How can I check that my change (commited into a bug-fix-branch) was merged into the stable-branch and also pushed to the server-repository?
So this really has 3 parts:
1) was it commited? when? See revision number with:
hg blame FILENAME
see the log with date and so on with:
hg log REVISION
2) was it merged?
hg glog -r "(merge() and branch(2.5) and children(branch('BRANCHNAME')))" \
--template "{branches} [{rev}] ({date|shortdate}): {desc|firstline}\n"
Could this be shorter?
3) was it pushed?

It can be shorter and cleaner (under some conditions)
Task 1
If you can recall any part of any string of you patch-work in any file - hg help grep. F.e (pattern is regexp, thus - brackets are escaped for processing "as is"):
>hg grep "repo\[None\].parents()" test_hooks.py
tests/test_hooks.py:1417: state = repo[None].parents()
Second field in output (easy parsable for auto-processing) is changeset in which this change was made in this file
Task 2
Just fix for rather dirty (and bad in common logic) revset:
with merge() and branch(DST) and children(branch('SRC')) you'll got all mergesets for merging SRC -> DST, even irrelevant to known revset of bugfix. Output for the above repository and your revset (note also slightly changed command - hg glog is deprecated)
>hg log -g -r "(merge() and branch(default) and children(branch('stable')))" --template "{branches} [{rev}] ({date|shortdate}): {desc|firstline}\n"
[839] (2011-10-19): Merge with stable.
[841] (2011-10-21): Merge with stable.
[843] (2011-11-01): Merge with stable
[982] (2012-11-11): Merge with stable.
[1021] (2013-06-23): Merge with stable.
[1108] (2014-02-11): Merge with stable.
[1126] (2014-02-12): Merge with stable.
[1171] (2014-04-04): Merge with stable.
[1180] (2014-05-02): Merge with stable.
[1228] (2014-08-01): Merge with stable.
[1231] (2014-08-12): Merge with stable.
[1257] (2014-11-05): Merge stable back into default.
[1266] (2014-11-15): Merge with stable.
[1280] (2014-12-10): Merge with stable.
[1307] (2015-01-30): Merge with stable.
[1326] (2015-05-08): Merge stable back into default.
[1335] (2015-05-29): Merge with stable.
[1338] (2015-07-08): Merge with stable.
[1341] (2015-07-09): Merge with stable.
[1346] (2015-08-11): Merge with stable.
[1349] (2015-09-26): Merge with stable.
[1358] (2015-09-30): Merge with stable.
[1362] (2015-10-21): Merge with stable.
[1367] (2015-12-31): Merge with stable.
[1372] (2016-01-27): Merge with stable.
[1378] (2016-03-04): Merge with stable.
[1410] (2016-05-11): Merge with stable.
[1418] (2016-05-23): Merge with stable.
[1489] (2016-06-26): Merge with stable.
I started with plain descendants(1417) (greedy revset, yes)
>hg log -r "descendants(1417)" -T "{rev}\n"
1417
1418
1419
1420
1421
...
because I'm interested in only in merges into default (in my case) possible shorter output will be hg log -r "descendants(1417) and branch(default)" (but it can be rather long too - I really eliminated two revsets) and only first revset from list needed
>hg log -r "first(descendants(1417) and branch(default))" -T "{rev}\n"
1418
Or in a little bit different way (recalling about mergesets entities, can also be first()-ed)
>hg log -r "merge() and descendants(1417) and branch(default)" -T "{rev}\n"
1418
1489
Notes:
Solution for p.3 - perform all tests on CENTRAL-REPO clone (which you have already, yes)
"Bad logic" remark - branch(2.5) and children(branch('BRANCHNAME') by design extract only mergesets in 2.5, merge() doesn't apply any additional effective filter
Addenda:
After some (still unfinished) headache I got the above command as alias with two parameters: problematic changeset and target-branch. It's something like
[alias]
ismerged = log -r "first(descendants($1) and branch('$2'))" --template "{ifeq(branch, '$2', 'Merged in {rev}','Not merged')}\n"
in repo's .hgrc
Output for merged changeset
>hg ismerged 62 default
Merged in 63
But I can't get else-part to work for not merged changesets and still have dumb empty output in this case
Future (more decorative, than functional) improvements may include:
transferring revset definition from alias into `[revsetalias]
getting good else-part of template

Related

Find changeset using commit message mercurial

I was wondering if I can find, in mercurial, a changeset using a part of a commit message
for example I have some commits with following messages:
"Test-254 modified some files"
"Test-256 added logs"
And I want to find the changeset which has a commit containing Test-254 or Test-256
Mercurial supports advanced selection language called revset. You can access the help with hg help revset.
It supports both predicates and operators.
Predicates are for example all() to match all revision or desc(string) to match revisions containing string in their message.
Operators are x:y for selecting a range or or for an or condition.
By combining both, you can select the right commits you want:
hg log -r "desc('Test-254')" will matches all revision that includes Test-254 in their message.
hg log -r "desc('Test-256')" will matches all revision that includes Test-256 in their message.
hg log -r "desc('Test-254') or desc('Test-256')" will matches all revision that includes either Test-254 or Test-256 in their message.

List all merged changesets since last merge?

Using Mercurial, how can I list all the changesets applied by merging a branch, since the last merge from that branch?
Revsets are your friend. Or your nemesis, depending on how complex they get :)
The following command will show all associated changesets between the last two merges:
$ hg log -r "first(last(merge(),2)):last(merge()) & ancestors(last(merge()))"
That complex little expression (which I'll look at making simpler later) does the following:
x:y gives you all changesets between x and y inclusive
merge() is a revset that contains all merges.
last(...,n) gives the last n changesets of a set, with n defaulting to 1
first(...) gives you the first changeset of a set
ancestors(last(merge())) is a set containing all ancestors of the last merge
Combining all of those, the expression above becomes (ready?): Give me all changesets between the first of the last two merges, and the last merge, inclusive, which happen to be contributing ancestors of the last merge.
The ancestors(...) bit filters out any changesets that are not related.
You can limit this to be the changes on a specific branch by adding & branch(branchname). For example, if you are merging onto a release branch from default, you could do:
$ hg log -r "first(last(merge(),2)):last(merge()) & ancestors(last(merge())) & branch(default)"
This wouldn't include the actual merges themselves, as they would appear on the release branch.
Hopefully this makes sense - I'll have a look this afternoon to see if I can get a simpler way, but that's the first that springs to mind. In the meantime, if you use this, you can make it easier by creating a revset alias in your user hgrc file:
[revsetalias]
contrib = first(last(merge(),2)):last(merge()) & ancestors(last(merge()))
So you can then use:
$ hg log -r "contrib"
$ hg log -r "contrib & branch(default)"
For more information have a look at hg help revsets.
I'm not sure icabod's solution is quite right. Let me see if I can explain.
Let's take this change graph.
o----A1----A2----M1--------A3---M2
\ / /
---B1----B2--- /
\ /
----C1--------C2----C3
B is a branch taken from o, and C is a branch taken from B1. If we're at M2 and run icabod's command then:
last(merge()) is M2
first(last(merge(),2)) is M1
So the expression becomes:
hg log -r "M1:M2 & ancestors(M2)"
M1:M2 is the changes made than have revision numbers between M1 and M2, which in this case is A3, C2 & C3, which completely ignores C1.
What I think is you're looking for the set of ancestors of M2, that weren't ancestors of M1. i.e.
hg log -r "ancestors(M2) & not ancestors(M1)"
or
hg log -r "ancestors(last(merge())) and not ancestors(first(last(merge(), 2)))"
I think this should be C1, C2, C3 & A3. It also has the advantage that it doesn't care how, or when, change-sets were added to the repo.
The only problem with this is if the second to last merge isn't an ancestor of the latest merge. I'll leave that as an exercise for the reader ;-)
Of course, all of this can be avoided by doing hg merge --preview (or -P) prior to doing a merge, and it lists all the change-sets that will be included when you do a merge.

How to show list of unapplied changesets in Mercurial

After pushing changesets to a repository called 'A' how can I see the list of changesets waiting to be applied when I am in 'A'?
Expanding on that,
In repo B I push changesets to repo B
I change to repo B
How can I list the changesets pushed in step 1?
Not sure what you mean by "unapplied" changesets, however here's a couple thoughts.
You can easily see what changesets will be pushed to a repository by doing hg outgoing prior to doing the hg push. This will list all of the changesets that will be pushed using default options.
Similarly you can use hg incoming in the destination repository to show what changesets would be pulled from another repo.
As for "unapplied" changesets, if I assume you mean changesets that are newer than the working directory, you could use hg log -r .:tip, which should (I've not had a chance to test it) show all newer revisions, but not actually all recently-pushed ones.
Edit: I've updated the revision set in the -r option to something that should work. Have a look at revsets on the Mercurial manpage for more possibilities.
$ hg summary
parent: 0:9f47fcf4811f
.
branch: default
commit: (clean)
update: 2 new changesets (update) <<<<<
The update bit tells you what (I think) you want.
I had written a different answer, but I ended up with a better way of doing what is needed here (an even better and definitive –for me– solution is at the end of this post, in the [EDIT] section).
Use hg log.
Specifically, issue an hg sum command first. This will give me:
parent: 189:77e9fd7e4554
<some commit message>
branch: default
commit: (clean)
update: 2 new changesets (update)
To see what those 2 new changesets are made of, I use
hg log -r tip -r 2 -v
Obviously, 2 is to be replaced with the number of changesets that hg sum reports.
This works because tip will refer to the most recent (or "unapplied") changeset. By limiting the output to the 2 latest changes (-l 2), the information is shown only for those changesets that I'm interested in. With -v, the list of files affected by the changeset is also shown.
To make things simpler, I have defined a user command in my .bashrc file:
alias hglog="hg log -r tip -l $1"
This allows me to type hg sum (to get the number of pending/unapplied changesets) and then to type hglog x where x is the number of changesets revealed by hg sum.
There is probably a more complete way of doing this, for instance using custom templates, but I guess it's pushing things too far in terms of sophistication.
[EDIT] (Third iteration)
I have reached the most satisfying answer to this question by expanding on the alias idea so that I no longer have to type hg sum. My .bashrc file now contains this:
show_pending_changesets() {
nb=$(hg sum | grep "update:" | sed 's/update: \([0-9]*\) .*/\1/');
if [ `expr $nb + 1 2> /dev/null` ] ; then
hg log -r tip -v -l $nb
else
echo "Nothing new to report"
fi ;
}
...
alias hgwhatsnew=show_pending_changesets
Explanation: I'm using sed to extract the number of changesets from the last line (which is the one that starts with update:) of the output of hg sum. That number is then fed to hg log. All I have to do then is to type hgw and tab-complete it. HTH

Mercurial - diff multiple changesets at same time?

To diff we use:
hg diff -c <xyz>: Show diffs for a given changeset
hg diff -r <xyz>: Show all diffs since a given changeset
But let's say you have changesets 4-5-6-7-8 where changesets 4, 6, 8 were related to a particular area of the system and in one diff you wanted to see the changes made from JUST these three changesets, how would you do this? If file A was modified in changeset 4 and 8, the diff would show the difference between changeset 3 and 8.
If changesets 4,5,6,7,8 are linear in history I don't think that even with revsets you can do that using just -r. However, if the changes in 5 and 7 really are from a different part of the system you can likely get the output you want by adding a -X or a -I. Something like this:
hg diff -r 3::8 -X part/you/do/not/want/**
or
hg diff -r 3::8 -I part/you/do/want/**
If, alternately, you're a little more exact about parenting a changeset as early as possible in history you'd have a topology like this:
[3]---[4]---[6]---[8]---[9]
\ /
------[5]---[7]------
and then you'd get what you want using:
hg diff -r 3::8
(note the double colon which tells the range to follow topology not just numeric range)

mercurial: test whether a branch contains a changeset

I wonder whether there is a mercurial command/extension that just tests whether a given changeset is in a branch. The command would be something like:
hg contains [-r branch] changeset_id
and should check whether the given changeset is in the current/given branch, returning just "Yes" or "No".
I know about the "debugancestor" command, but a "Yes/No" answer is way easier to read.
And if there is, is it possible to check for transplanted changesets as well?
EDIT: The scenario is located in a repo where named branches have multiple heads. Lets say a branch is named "dev-X", having more than 1 head and a longer history, too long at least to track it with various graph visualizations.
I want to figure out whether a changeset X in branch "dev-X" was merged into another head of "dev-X". Therefore I cannot use branch names but only changeset numbers/hashes to specify a branch.
And to top it all, I'm trying to find out whether changeset X was transplanted there, possibly taking more than 1 transplantation step. I know that the necessary info is stored in mercurial (I've seen it when tampering with the mercurial internals), it's just not accessible via the command line interface.
How about this:
hg log -r changeset_id -b branchname
That will give some output if changeid_id includes changes on branch branchname, otherwise no output is returned.
You could wrap it in a bash function if you want:
function contains() {
if [ "$(hg log -r $1 -b $2)" == "" ]
then
echo no
else
echo yes
fi
}
which does this:
$ contains 0 default
yes
$ contains 0 other
no
using 1.6 and later with the power of revision sets all you need is
hg log --rev "ancestors(.) and <revNum>"
eg
hg log --rev "ancestors(.) and 1234"
blank means no, output means yes, its in your history. Some of the other solutions posted here wont work if the changeset was created in a named branch, even if it was merged at some point later.
As mentioned in the comment above I gave it a shot, this is what came out:
http://bitbucket.org/resi/hg-contains/
It should be pretty easy to transform the results from debugancestor into a yes or a no (but there's definitely no built-in way to do that; write a script already!). Be aware that the answer might be wrong if the branch has more than one branch head, though.
(Writing an extension to add a command to do this should also be nigh-trivial, BTW.)
You could always just print out the name of the branch for that revision (it'll be empty if it's default) and then test that against whatever you want (in bash or in a scripting language of some sort):
hg log --template '{branches}' -r <revision name/number>
I've tested most of approaches above, did not work. The extension 'contains' somehow takes wrong revision (I think its a bug), the hg log --rev "ancestors(.) and 1234" work, but I found even more simple approach to do this:
hg merge -P <changeset>
Will show you if anything unmerged remains (it will also include changesets which are not merged parents of the changeset in question)