mercurial revert file in subrepo - mercurial

If I do
hg revert subrepo/foo
then it fails as I need to specify -R for the subrepo. I'd rather not have to do this so I wrote a script to do it. Works fine, but I hope/wonder if there is a better way?
#!/bin/bash
for file in $*; do
repo=$(echo $file | cut -d'/' -f-1)
file=$(echo $file | cut -d'/' -f2-)
if [ -f $repo/$file ]; then
hg revert -R $repo $repo/$file
fi
done

Related

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

Is there a way to push all bookmarks to another repo, all at once? (Mercurial)

I am importing one Mercurial repo into another, maintaining history. There are several bookmarked heads on the default branch, and I want those bookmarked heads to still be bookmarked in the new, merged repo. As far as I can tell, the two ways to do this is to either,
pull each bookmark individually
pull the entire thing and recreate the bookmarks by hand.
Extending the previous answer, here's how to push all branches using awk and the output of hg bookmarks in bash:
hg bookmarks | awk '{if (NF == 3) print $2; else print $1;}' | xargs -n 1 hg push -f -B
Unix:
hg push $(hg bookmarks -T "-B {bookmark} ")
Windows:
for /f "delims=" %A in ('hg bookmarks -T "-B {bookmark} "') do #hg push %A
PowerShell:
hg bookmarks -T "{bookmark}\n" | %{ Write-Host === Bookmark $_ === ; hg push -B $_ }
-B parameter can be used in push any amount of times. Full bookmarks list for repo you can get from hg bookmarks

Tortoise HG - Add a tag on commit

At the moment, I only know how to add a tag after a commit. This means that a get a second commit that just contains the tag. Is it possible to add a tag on commit?
No, because a tag is an entry in the .hgtags file at the root of your repository containing the changeset id and the tag name, and this file itself is under revision control. The changeset id isn't known until the changeset is created, so tagging creates another changeset to check in the .hgtags file recording the tag for that changeset.
According to mercurial wiki, it is impossible. Just like Mark said.
https://www.mercurial-scm.org/wiki/Tag
But then, i just wondering. Why not mercurial ignoring the .hgtags file altogether ? just like it ignores .hg/ folder.
So mercurial won't include .hgtags everytime it's generating a changeset ID.
Would be great if .hgtags, .hgignores, etc is resides inside .hg/
For my point of view, Hg tagging system is a bit messy because creating a tag changes the history and needs merging and committing even if no project file has changed. Tagging can burden a history graph very quickly.
I was used of SVN tagging which was done on a separate branch, which has the advantage not to change working branch history. Moreover, tagging can be done from any branch, because Hg takes tags from the .hgtags files on the heads of all branches.
The little script below creates a branch "tagging" and puts tags in it. It merges the current branch in "tagging" branch, so it's easy to see the changeset tag was done from (it especially avoids long refreshes when switching branch).
It can probably be improved, but it suits my needs.
I strongly recommend making a clone of your project before testing this script, in case it does not behave as you expect!
#!/bin/bash
function echo_red()
{
echo -n -e "\e[01;31m"
echo -n "$1"
echo -e "\e[00m"
}
export -f echo_red
# Display the help and exit
function show_help {
echo "Usage: $0 [hg_tag_options ...]"
echo " tags a version (current if not specified) in the 'tagging' branch."
echo " Options are the 'hg tag' ones, plus"
echo " -?, -h, --help Show (this) help"
exit 1
}
# Parse the command-line arguments
function parse_args {
for arg in "${commandline_args[#]}"
do
case "$arg" in #(
'-?' | -h | --help )
show_help
;;
esac
done
}
commandline_args=("$#")
if [ "$commandline_args" = "" ]
then
show_help
fi
parse_args
VER=`hg id | sed 's#\([0-9a-z]*\).*#\1#g'`
BRANCH=`hg branch`
# Check for clean directory
TEST=`hg st -S -q`
if [ "$TEST" != "" ]
then
echo_red "Directory contains unresolved files !"
exit 1
fi
hg update --check >/dev/null
if [ $? -ne 0 ]
then
echo_red "Directory contains unresolved files !"
exit 1
fi
# Switch to tagging branch
hg update tagging >/dev/null
if [ $? -ne 0 ]
then
echo "Creating new 'tagging' branch."
hg update default >/dev/null
hg branch tagging
fi
# Merge if changes detected
TEST=`hg diff -r $VER -X .hgtags --stat`
if [ "$TEST" != "" ]
then
#take only the 'tagging' version of hgtags
cp .hgtags .hgtags.bak
hg merge -r $VER --tool internal:other >/dev/null
rm .hgtags
mv .hgtags.bak .hgtags
hg commit -m Merged
fi
# Tag and Switch back to original
hg tag -r $VER $#
hg update $BRANCH >/dev/null
hg update $VER >/dev/null
Example Usage:
hg_tag.sh [-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] test_v1_5
Not sure if this is what you are looking for, but you can move the tag to a different changeset.
hg com -m "moving tag to this changeset"
hg tag 0.1 -f
hg push

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