Mercurial: get report with current repository state - mercurial

I use a Mercurial integration repository with several sub-repositories. Is there any command to get some kind of report or overview of the current repository state?
I would like to get the actual hash code of every repository and changed files within the sub repositories.

The status command is aware of sub-repositories and will list every file in the main and all of its sub-repos:
hg status --subrepos
In its output it assumes that every subrepo has checked-out the revision as recoreded in the .hgsubstate file in the main repo; otherwise it shows the diff wrt that version for the respective subrepo.
I know no nice solution to check for the proper version being checked out. However you can obtain that with a bit of bash foo:
for i in $(cat .hgsubstate | cut -f2 -d\ ); do
if [ "$(hg log -r. -R$i --template='{node}')" != "$(cat .hgsubstate | grep $i$ | cut -f1 -d\ )" ]; then
echo "$i has different checked-out version"
fi
done

Related

Show if the revision of subrepos changed, or if they are dirty

I have a mercurial repository (main repo) with several sub repositories.
I need a mercurial command to show if the revision of a sub repo changed (including information on old and new revision) in the working copy or if the sub repo state is dirty.
How can I do this?
Most mercurial commands accept the -S or --subrepos flag. Thus by calling hg st -S you get a list of all changed files which include those in the sub-repos, if their state differs from the state recorded in the .hgsubstate file:
$ cd opengfx/
$ hg st
$ hg id
10065545725a tip
$ cd ..
$ hg st -S
M opengfx/.hgtags
M opengfx/Makefile
A opengfx/lang/japanese.lng
$ cat .hgsubstate
785bc42adf236f077333c55c58490cce16367e92 opengfx
As to your wish to obtain the actual revisions, that's AFAIK not possible with one command. However you can always check the status of the individual sub-repos like above or can check them from the main repo by giving mercurial another path to operate on:
$ hg id -R opengfx
10065545725a tip
In order to get the status of each repo compared to what is required by the parent repo, I'd resort to some simple bash:
for i in $(cat .hgsubstate | cut -d\ -f2); do echo $i is at $(hg id -R $i) but parent requires $(cat .hgsubstate | grep $i | cut -d\ -f1); done
which gives output like
opengfx is at 10065545725a tip but parent requires 785bc42adf236f077333c55c58490cce16367e92
In a similar fashion you can also check whether the state is modified by using hg st instead of hg id.

hg command to list subrepositories

Is there a command that can be constructed to list all the subrepositories of a Mercurial repository? Something like what the git submodule command does? (I am attempting to process them programmatically.)
As far as I can tell, the best option currently is to write a parser that processes .hgsub (dealing with the various optional sections like [subpaths]) and that seems much less optimal than relying on hg to parse the file. But I can't find a command that does it.
Is there one?
You can use the onsub extension. The repository linked in the Mercurial wiki disappeared, but I found https://bitbucket.org/kvaster/onsub which looks maintained.
I created a mini repo with two subrepos as follows:
$ find . -type d -name '.hg'
.hg <== outer repo
nested/.hg <== subrepo
nested2/.hg <== subrepo
The corresponding .hgsub is very simple:
nested = nested
nested2 = nested2
Example 1:
$ hg --config extensions.onsub=~/src/onsub/onsub.py onsub --verbose "hg status"
executing 'hg status' in nested
executing 'hg status' in nested2
Example 2:
$ hg --config extensions.onsub=~/src/onsub/onsub.py onsub "hg root"
/Users/hello/tmp/foo/nested
/Users/hello/tmp/foo/nested2
Example 3: using environment variables provided by onsub:
$ hg --config extensions.onsub=~/src/onsub/onsub.py onsub "echo; set | grep HG_"
HG_REPO=/Users/hello/tmp/foo
HG_SUBPATH=nested
HG_SUBURL=nested
HG_REPO=/Users/hello/tmp/foo
HG_SUBPATH=nested2
HG_SUBURL=nested2
As usual, you can get help with:
hg --config extensions.onsub=~/src/onsub/onsub.py help onsub
The --config ... on the command-line shows how to enable an extension without editing your $HOME/.hgrc.
Instead of parsing .hgsub I'd parse .hgsubstate instead - it is guaranteed to have one line per subrepository instead:
for i in $(cat .hgsubstate | cut -d\ -f2); do echo $i; done

Is there a way to see the most recent Mercurial revision for each file in a directory?

When you do hg log on a file, only the revisions that underwent changes are listed. I'd like to see what the most recent revision for all of the files in a directory is. (Think hg blame at a file level rather than a line level.)
I had thought that hg log -l 1 * might work, but it just shows the most recent revision across all of the files.
Here's the kind of output I'd like to see:
> hg blame --files
foo: 15
bar: 2
baz: 15
README: 1
Another alternative is to use a combination of hg status and hg log, like this:
for FILE in $(hg status -nA); do
hg log -l1 --template '{rev}\t' "$FILE"
echo $FILE
done
I suspect that if you want to use hg directly to do this, you'll need to write an extension (but I'm by no means an expert here). But would something like this work, if you're willing to use a script?
for x in *; do
highest=`hg blame "$x" 2>/dev/null | cut -d : -f 1 | sort -nr | head -n1`
if [ "$highest" ]; then echo "$x: $highest" ; fi
done
The obvious downside here is that this is pretty slow.

Can Mercurial do a reverse-patch?

Scenario: I've "inherited" a program, kept under Mercurial, that only works on my system with specific tweaks to certain files that are checked in. I do not want to check these tweaks in.
My most recent solution to this is to create a mercurial patch file (hg diff > patchfile) containing these tweaks; when I need to check in my changes, I'll just reverse-apply the patch, commit, and re-apply the patch. (If I had full control of the source, I'd just move all these little tweaks to a single configuration file that isn't under version control, putting a "sample" config file under version control)
Unfortunately, it seems that while the GNU patch command supports the --reverse flag, it does not support hg's multi-file diff format as a single patch file (or maybe it does, and I just don't know the switches for it?). OTOH, hg has its own patch command that can apply the diff, but that doesn't support any kind of reverse flag.
So my question is twofold:
How should this be done in mercurial? Surely hanging on to a "tweak patch" isn't the only way to handle this situation. Maybe mercurial has a plugin or something built in for such temporary, uncommittable changes.
Aside from how things should be done, is there any way to reverse-apply such a mercurial diff-patch to a mercurial repo like this? There are other situations where such functionality would be useful.
Mercurial's patch command (really import) doesn't support reverse, but hg diff does. Use --reverse on that and you'll have a reversed patch that Mercurial can apply.
However, what you're describing is a very common vendor-branch style workflow, which mercurial can better support using features other than diff and patch.
Specfically, Mercurial Queues does exactly what you want.
I found --reverse approach did not work when you have sub repos. i.e.
hg diff --reverse -S
. In case it helps anyone, this barely tested script seems to do the job:
#!/bin/bash
DIRS="$*"
if [[ $DIRS = "" ]]; then
DIRS=$(echo *)
fi
for arg in $DIRS; do
arg=$(echo $arg | sed 's/^\.\/*//g')
repo=$(echo $arg | cut -d'/' -f-1)
grep -q "^$repo = " .hgsub 2>/dev/null
if [ $? -eq 0 ]; then
if [ -d $repo ]; then
cd $repo
hg diff --reverse | sed -e "s;--- a;--- a/$repo;g" -e "s;+++ b;--- b/$repo;g"
cd ..
else
echo Error, unknown repo $repo
fi
else
hg diff $arg --reverse
fi
done

In Mercurial (hg), how do you see a list of files that will be pushed if an "hg push" is issued?

We can see all the changesets and the files involved using
hg outgoing -v
but the filenames are all scattered in the list of changesets.
Is there a way to just see a list of all the files that will go out if hg push is issued?
First, create a file with this content:
changeset = "{files}"
file = "{file}\n"
Let's say you call it out-style.txt and put it in your home directory. Then you can give this command:
hg -q outgoing --style ~/out-style.txt | sort -u
A somewhat under-appreciated feature: hg status can show information about changes in file status between arbitrary changesets. This can be used to get a list of files changed between revisions X and Y:
hg status --rev X:Y
In this case, we can use hg outgoing, to find the first outgoing changeset X and then do
hg status --rev X:
to see the files changes since revision X. You can combine this into a single line in your shell:
hg status --rev $(hg outgoing -q --template '{node}' -l 1):
I usually use
hg outgoing -v | grep files
It makes the listing shorter, but doesnt sort. But thus far I havent been in a situation where I want to push so much (and at the same time check the files) that its been a problem.
[Edit]
To do what you want:
Use cut to remove the files: part
For changesets with more than one touched file, use tr to put them on separate lines
Finally sort the resulting output with sort
Like so:
hg outgoing -v |grep files: |cut -c 14- |tr ' ' '\n' |sort -u
You can put this in ~/outgoingfiles.sh or something to have it nice and ready.
I use Torgoise Hg, which is a shell extension that has a "synchronize" view allowing you to see outgoing files before you push them. It's convenient for commits as well, and other things.
A simple hg out will also solve this.
It will list all committed but yet to push checkins.