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)
Related
As hg help grep says:
By default, grep prints the most recent revision number for each file in
which it finds a match. To get it to print every revision that contains a
change in match status ("-" for a match that becomes a non-match, or "+"
for a non-match that becomes a match), use the --all flag.
This works as advertised: When I run hg grep --all pattern, I get a list of hits marked with :+: or :-::
plaintext.py:8055:+: ...
plaintext.py:4690:-: ...
otherfile.py:4690:-: ...
plaintext.py:4630:+: ...
plaintext.py:4630:+: ...
The problem is when I try to restrict the search to a branch or revset:
hg grep --all -r 'branch(default)' pattern
The above will no longer print the revisions in which there is a change of status. Lots of revisions that match are printed (not just the most recent or most ancient one), and many revisions that removed a match (marked with :-:) are no longer printed. (Some :-:-revisions are still printed; I don't understand when this happens.)
This seems like it could be a bug, but what do I know. I'm using mercurial 4.2 (on OS X).
I could live with filtering the output of unrestricted hg grep --all; but the default format does not include the branch (and I do know know enough to write a template that includes all the current information plus the branch).
I think you're running into this bug:
https://bz.mercurial-scm.org/show_bug.cgi?id=3885
Unfortunately "hg grep" is notoriously buggy and likely needs lots of work to get into a place where it's more usable.
So my coworker just won the hash lottery. We create a feature branch for every ticket we resolve, following the convention b##### where ##### is the issue number.
The trouble is that when he tried updating to that branch (before it existed) via hg up branch(b29477), it took him to default instead of saying that the branch doesn't exist.
It turns out that branch(b29477) actually returns the name of branch of the thing inside the parens (instead of forcing Mercurial to evaluate the thing inside the parens as a branch name as I thought!), and there so happened to be a changeset beginning with b29477 which was on default, so instead of saying the branch didn't exist, it took him to the tip of default!
Now we can work around this problem by choosing a different branch name, but I want to know if there's any way to hg update <branch_name_and_dont_interpret_this_as_anything_else>?
BTW, hg log also lies about what it's --branch parameter does. It says:
-b --branch BRANCH [+] show changesets within the given named branch
But that's not true at all. Go ahead and run it with a hash. e.g.,
hg log --branch eea844fb
And it will turn up results. If you dig through the docs, you'll discover that it's actually the same as:
hg log -r 'branch(eea844fb)'
Try this:
hg update -r "branch('literal:b29477')"
From the Mercurial help page:
branch(string or set)
All changesets belonging to the given branch or
the branches of the given changesets.
If string starts with re:, the remainder of the name is treated as a
regular expression. To match a branch that actually starts with re:,
use the prefix literal:.
This means that if you use the literal prefix, you are specifying a string. And a string is not a set.
As the text says, if you specify a changeset, Mercurial will show:
the branches of the given changesets
Can you help me to create a proper revset for mercurial hg status ?
I would like to list all the files that were changed in the current branch since it was created.
I tried
hg status --rev "branch(foo)"
where foo is the name of my branch, but this also lists files that were changed in the branch from which my branch was created (?).
I don't get how to create a proper revset for this.
I created my branch and made several changes in multiple files. Now I want to reload these files in my application, but only them.
This seems pretty straightforward (see hg help revsets and hg help revisions for where this comes from).
We might start with the set of all commits in a branch, e.g., for branch foo:
-r 'branch(foo)'
Obviously this can produce a dozen, or even a million, revisions; but you want to see what happened between "branch creation"—which needs to examine the parent of the first such revision—and "current status of branch", which needs to examine the last such revision.
The first1 revision of a large set is obtained by first() and the last by last(). However, when various commands are given a revision specifier, they look it up as a single revision, and here a branch name suffices to name the last commit on the branch anyway.
To get the (first) parent of a revision, we use the p1() function (the suffix ^ is only allowed on a literal revision, not a function that returns a revision). Hence the parent of the first revision on branch foo is:
-r 'p1(first(branch(foo)))'
To get a full diff of this against the last commit in the branch:
hg diff -r 'p1(first(branch(foo)))' -r 'foo'
But you don't want a full diff, you want the file names. The command that produces this is hg status, and it has a slightly different syntax:
hg status --rev 'p1(first(branch(foo)))' --rev 'foo'
The status includes the letters at the front, as well as the names: A for newly added files, M for modified files, and so on. Note the use of --rev rather than just -r (in fact, you can use --rev with hg diff as well).
Note that there's a much shorter syntax, ::foo, that gets all the ancestors of the given branch up to and including the last revision in the named branch. However, this gets too many ancestors. You can, however, use p1(first(branch(foo)))::foo as the (entire) argument to --rev, and this also works. so:
hg status --rev 'p1(first(branch(foo)))::foo`
is a slightly shorter way to express this.
Last, note that comparing the first commit in the branch to the last (as would happen with hg status --rev 'first(branch(foo))' --rev foo, for instance) can miss changes made in that first commit on the branch. That's why we use p1 here.
1The first function selects the first in the set, which may not be the same as the numerically-first revision. For instance, suppose the set is made from x | y and a revision in y is numerically lower than a revision in x, or you use reverse(branch(foo)) to put the commits in high-to-low order. In this case, min instead of first would be the function to use.
This question already has an answer here:
How do I find the merge that moved my changeset to another branch?
(1 answer)
Closed 9 years ago.
I am looking for a way with TortoiseHg (or plain hg if no other possibility exists) to locate all the changes to a particular file.
I've tried using a revision set query:
merge() and file("path/to/filename.cs")
but that didn't get me what I'm looking for. It returns an empty set. I assume this is because merge() only returns merges, and file() only (appears to) returns non-merges, so the intersection is empty.
I've also tried modifies(pattern) but that doesn't appear sufficiently different from file(pattern) (looks to me like file() is the union of adds() and modifies()). contains(pattern) doesn't return any elements at all.
So, is it possible to get a list of changesets in which a particular file has been modified in any way?
It looks like you're running into the "how did my change get into this branch" problem. When you merge a changeset into a branch, Mercurial doesn't record that as a change. Instead, it makes a note that the merged changeset is now part of the destination branch. The only time a merge will show that a file was modified is if there was a merge conflict, which results in a new changeset.
Finding what merge brought a changeset into a branch is a two step process. First, you have to find the changeset where the change you're interested in occurred.
hg log -r "file('<PATTERN>')
Once you have that revision, find the first descendant changeset in the destination branch:
hg log -r "first(branch(<BRANCH>) and descendants(<REVISION>))"
hg log -r "branch(BRANCH) and file('PATTERN')"
Revset also can be used and entered into Filter Tooolbar in THG Workbench
hg log grep name_of_your_file
Does the trick for me in terms of finding all the change sets that have resulted in a change to a given file. Of course if you would like something pretty:
thg log name_of_your_file
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