How to forget all removed files with Mercurial - 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

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

Can I disable the default behaviour `hg add` with no arguments?

When I run hg add with no arguments, it is always by mistake, and the result, adding all of the files and directories recursively, is horribly annoying and difficult to undo, especially when other files have been (correctly) added since the last commit. Is there any way to make a plain hg add just print an error message?
Try putting this in your ~/.hgrc:
[defaults]
add = -X .
That tells hg add that unless specifically named it should ignore all files (got matches all). Here's an example:
(df)Ry4ans-MacBook-Air:~ ry4an$ hg init test
(df)Ry4ans-MacBook-Air:~ ry4an$ cd test/
(df)Ry4ans-MacBook-Air:test ry4an$ vi ~/.hgrc # added the section above
(df)Ry4ans-MacBook-Air:test ry4an$ hg status
(df)Ry4ans-MacBook-Air:test ry4an$ echo this > that
(df)Ry4ans-MacBook-Air:test ry4an$ hg add # nothing added
(df)Ry4ans-MacBook-Air:test ry4an$ hg status
? that
(df)Ry4ans-MacBook-Air:test ry4an$ hg add that
(df)Ry4ans-MacBook-Air:test ry4an$ hg status
A that
In general though, you should just make your .hgignore robust enough to ignore all the files you don't want added
In your user config file (~/.hgrc), add the following to your [alias] section:
[alias]
realadd = add
add = add --dry-run
Now, just hg add will always do a dry-run. To actually add, you have to use hg realadd. Note that you could redefine the add alias to do anything, it doesn't have to be add --dry-run.
I don't know a way to do this purely with Mercurial configuration, but if you're willing to tune your bash profile, then you can redefine the hg command as a function. The function would either detect hg add and fail or otherwise do a passthrough to the real hg command.
function hg() {
if [ "$#" -eq 1 ] && [ "$1" = "add" ]; then
echo "hg add with no arguments denied" 1>&2
false # sets exit code to 1, but doesn't close process like exit would
else
command hg $#
fi
}
Here is what it looks like in action after I source in the new function from my profile:
hg > /dev/null; echo $?
0
hg add > /dev/null; echo $?
hg add with no arguments denied
1
hg add . > /dev/null; echo $?
0
hg status
touch afile
hg add afile
hg status
A afile
You can undo a global add using the following command:
hg forget $(hg status -an)
Here, hg status -an will list all added files. hg forget will then remove those files from the list of added files.
You can also create an alias for this in your .hgrc, e.g.:
[alias]
unadd = !$HG forget $($HG status -an)
Note that this will also delist all previously added files that you did mean to add, so you may have to redo that.
Also, operating systems and shells have limits for how many arguments can be passed to a command. If you run into this limit because you accidentally added more than a few thousand files, you can use xargs instead:
hg status -an | xargs hg forget
Or, as an alias:
[alias]
unadd = !$HG status -an | xargs $HG forget

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

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