Any way to pull/update all subrepos? - mercurial

I'm looking into the viability of switching from svn to mercurial for my organization, but there's one hangup I can't seem to find a solution for.
Is there any way to pull and update a repo and all subrepos without manually pulling and updating each one?
I'd like to switch to mercurial, but if that's not possible then it's a no-go for us.
Edit: Good god I must be tired today... two questions on SO for which I find the answers minutes after asking...

Somehow missed this, and found it right after asking the question:
https://www.mercurial-scm.org/wiki/OnsubExtension

You can define a simple shell alias like the following
alias hgsub='find . -name ".hg" -type d | grep -v "\./\.hg" | \
xargs -n1 dirname | xargs -n1 -iREPO hg -R REPO '
and then do
hgsub tip
hgsub pull -u

As an alterantive, a batch script might help:
#echo off
for /D %%d in (*) do (
if exist %%d\.hg (
echo Verzeichnis %%d
cd %%d
hg pull -u
echo ----------------------------------------------
cd ..
)
)
pause

Related

How to commit many numbered old versions of a file

I'm looking for an elegant way to populate Mercurial with different versions of the same program, from 50 old versions that have numbered filenames:
prog1.py, prog2.py ... prog50.py
For each version I'd like to retain the dates and original filename, perhaps in the change comment.
I'm new to Mercurial and have searched without finding an answer.
hg commit has -d to specify a date and -m to specify a comment.
hg init
copy prog1.py prog.py /y
hg ci -A prog.py -d 1/1/2015 -m prog1.py
copy prog2.py prog.py /y
hg ci -A prog.py -d 1/2/2015 -m prog2.py
# repeat as needed
One can of course automate the whole thing in a small bash script:
You obtain the modification date of a file via stat -c %y ${FILENAME}. Thus assuming that the files are ordered:
hg init
for i in /path/to/old/versions/*.py do;
cp $i .
hg ci -d `stat -c %y $i` -m "Import $i"
done
Mind, natural filename sorting is prog1, prog11 prog12, ... prog19, prog2, prog21, .... You might want to rename prog1 to prog01 etc to ensure normal sorting or sort the filenames before processing them, e.g.:
hg init
for i in `ls -tr /path/to/old/versions/*.py` do;
cp /path/to/old/versions/$i .
hg ci -d `stat -c %y /path/to/old/versions/$i` -m "Import $i"
done

How do you check if a mercurial repo is in a clean state?

As a user, I usually use hg st to check the status of a repo, and verify that it is in a clean state, with no modified files.
Here I would like to do this programmatically. I know I can also use hg st for that, but the output is less than ideal for consumption by a computer program. Is there a better way to check whether a mercurial repo is in a clean state?
If you issue the hg identify --id command, it will suffix the ID with a + character when the repository has modified files. (Note: this flag does not report untracked files.)
If you grep the output of this command for the + character, you can use the exit status to determine whether there are modifications or no:
$ hg init
$ hg identify --id | grep --quiet + ; echo $?
1
$ touch a
$ hg identify --id | grep --quiet + ; echo $?
1
$ hg add a
$ hg identify --id | grep --quiet + ; echo $?
0
You should use hg summary:
$ hg init
$ echo blablabla > test.txt
$ hg summary
parent: -1:000000000000 tip (empty repository)
branch: default
commit: 1 unknown (clean)
update: (current)
Most major programming languages have HG APIs you can access.
This answer might be useful for other people searching this topic:
I agree to #SteveKayes comment above that hg status is a good command for programmatic consumption.
Here is an example how to use it in a bash script:
#!/bin/bash
set -e
cd /path/to/hg-repo
repo_status=`hg status | wc -l`
if [ $repo_status -ne 0 ]; then
echo "Repo is not clean"
else
echo "Repo is clean"
fi

How to forget all removed files with Mercurial

I am new to Mercurial and after a cleanup of the image folder in my project, I have a ton of files showing with ! in the 'hg status'. I can type a 'hg forget ' for each, but there must be an easier way.
So how can I tell mercurial to forget about all the removed (status = !) files in a folder?
If you're also okay with adding any files that exist and aren't ignored then:
hg addremove
would a popular way to do that.
With fileset (Mercurial 1.9):
hg forget "set:deleted()"
In general, on Linux or Mac:
hg status -dn | while read file ; do hg forget "$file" ; done
Or, if your shell allows it, if there are not too many files, and if the filenames do not contain spaces or special characters, then:
hg forget $(hg st -dn)
I
You can try:
hg forget -I '*'
in order to include all files in your forget command.
By using the -d flag for status, which displays missing files:
for file in $(hg status -d | cut -d " " -f 2); do echo hg forget $file; done
Run this in the root of your repo, and if you're happy with the results, remove the echo
This has the bonus over the accepted answer of not doing any additional work, e.g. adding a bunch of untracked files.
more shorter instead of
for file in $(hg status -d | cut -d " " -f 2); do echo hg forget $file; done
this
hg status -d | cut -d " " -f 2 | xargs echo hg forget # test case
hg status -d | cut -d " " -f 2 | xargs hg forget # real work

Testing for uncommitted changes in mercurial

What's the best way to check in script if there're uncommitted changes in mercurial's working tree.
(the way I would with git diff --quiet in git)
In mercurial 1.4 and later you can use the summary command, which gives output like this when changes exist:
$ hg summary
parent: 0:ad218537bdef tip
commited
branch: default
commit: 1 modified
update: (current)
and this post-commit:
$ hg summary
parent: 1:ef93d692f646 tip
sfsdf
branch: default
commit: (clean)
update: (current)
Alternately, you could install the prompt extension and do something like this:
$ hg prompt '{status}'
which will output a ! or ? or nothing as appropriate.
Both of those, of course, are just alternate text outputs. I couldn't find anything that used the exit code directly, but since $? checks the last command in a pipe you could do?
hg summary | grep -q 'commit: (clean)'
which will set $? non-zero if any changes are uncommitted:
$ hg summary | grep -q 'commit: (clean)' ; echo $?
0
$ echo more >> that
$ hg summary | grep -q 'commit: (clean)' ; echo $?
1
You can also run hg id. If the hash ends with a + it indicates the working copy has changes. This should even work with old versions of hg.
It sounds like you're already using zsh; well, a couple days ago I helped to update the Mercurial support for the built-in VCS_INFO for putting VCS info in your prompt. Slated for the next release is support for showing changes to the working directory (among other things). If you don't want to wait you can grab the necessary files from CVS.
At the moment my prompt includes this (using only built-in zsh functionality):
(hg)[1801+ branchname somemq.patch, anycurrentbookmarks]
I use:
hg status -m -a -r -d -u
If no changes with tracked files, then the command output is an empty string.
I use this bash-snippet for some time now:
if [[ $(hg status 2>/dev/null) ]]
then
# do something
fi
Both id and summary are slower than status, so this is the fastest way I currently know, ignoring untracked files:
[[ -z `hg status | grep -v '^?'` ]] && echo no-changes || echo has-changes
There should be something more elegant than simply
[ `hg st |wc -l` -eq 0 ] && echo hi

How do I delete all untracked files from my working directory in Mercurial?

Is it possible to delete all untracked files from my working directory? Let's say I added a bunch of files to my working directory, didn't add them via 'hg add' and now want to get rid of those new files entirely?
I'm on windows, although I'm using PowerShell, so a combined solution is also possible here.
Add the Mercurial Extension called purge. It is distributed by Mercurial.
This extension adds a “purge” command to “hg” that removes files not known to Mercurial. i.e. untracked Files. So your command would be,
hg purge
It is not enabled by default, maybe to avoid accidentally removing files that you forgot to add.
To install this extension, add this to your mercurial settings file (.hgrc on Unix, Mercurial.ini on Windows)
[extensions]
purge =
To enable this extension temporarily you can use
hg purge --config extensions.purge=
The proper way without purge is:
hg st -un0 | xargs -0 rm
Thanks! This worked for me also in Powershell:
hg st -un | rm
rm $(hg st -u)
...where -u stands for "untracked" you can also pick another state.
You can use
hg purge --all
to remove all the ignored and untracked files
(first you need to install the purge extension as explained in some answers)
Try following:
hg st -un | xargs rm
if you don't want to use purge:
rm $(hg st | grep ^? | awk '{print $2}')
This should do the trick:
hg status | grep '^\?' | sed 's/^\? //' | xargs rm -rf
Assuming that you are using a *nix system you could run something like this:
rm `hg st | awk '/\?/ {print $2}'`
from the root of the mercurial repository.
I don't know of a standard mercurial command to achieve the same but I believe there are many more command-line options to do this. I'm sure there are "better" solutions and would be interested to hear any other suggestions.
Please use this command with caution as it was not thoroughly tested.
This works from Windows 10 command line (used cautiously of course):
for /f %g in ('hg status -un') do #echo %g & #del %g
A quick/hacky way, if you do not have local changes, is to delete the folders you want from the file manager (Windows explorer for example) and then use "hg revert" which restores only the tracked files.