Simple way to revert .orig files? - mercurial

I've just gone and accidentally run hg revert *. Does Mercurial come with a tool to move all the .orig files back into place?

No. If you're in bash you can always do:
for thefile in *.orig ; do cp -v $thefile ${thefile%%.orig} ; done

This command will reinstate your .orig files from anywhere inside your repo:
find `hg root` -name *.orig -exec rename -f 's/.orig//' {} \;
You can add a hg alias for this in your .hgrc like so:
[alias]
reinstate= !find `$HG root` -name *.orig -exec rename -f 's/.orig//' {} \;
And then run it from your repo using this command:
hg reinstate

No, but your operating system probably provides cp command (or equivalent). Just copy .orig onto reverted file, or, if you've commited the file in the wanted version, revert it again from that version.

Related

Mercurial: rename using --include option

I am trying to move(via the rename tool) a group of source files but still keep them tracked. Mercurial's rename tool has the --include option for handling multiple names. When I a try to move the files, I get the current directory added to the final name. When I remove the preceding "./" only the file name is referenced.
I am using the -I option to include a pattern of files. For reference:
https://www.selenic.com/mercurial/hg.1.html#rename
I am using Mercurial on windows through Cygwin64.
This is the directory that I am in:
$ pwd
/cygdrive/c/Users/me/thisProject/apple
This is what I want.
$ hg rename -f -v -I '*.c' ./ banana
moving one.c to .banana\one.c
moving two.c to .banana\two.c
moving three.c to .banana\three.c
This is what I don't want.
$ hg rename -f -v -I '*.c' ./ ./banana
moving one.c to banana\apple\one.c
moving two.c to banana\apple\two.c
moving three.c to banana\apple\three.c
Why does adding a "./" to the destination add the current directory name as an extra folder in the output?

How to drop a prefix from hg archive?

I would like to export files from a repository, ignoring changes in the working tree. Furthermore, rather than exporting everything, I would like to see a subset of it. The destination directory might already contain some files and those must be overwritten.
Given:
project/some/sub/dir/
I would like to export it to:
output/dir/
In git, I can use:
git archive --prefix=dir/ HEAD -- some/sub/dir/ | tar -xv -C output
What is the equivalent command in hg? If I use hg archive -t files -I some/sub/dir output/, then I get output/some/sub/dir. I could pipe the result through tar, but then I have to manually calculate the prefix that should be dropped:
hg archive -t tar -I some/sub/dir/ - |
tar -xv -C output --strip-components=3
(in reality, I have some other tar patterns that should be ignored such as --exclude='.*'). Any ideas? This export will be done for three other directories located in the repository.
Current situation:
srcdir=some/sub/dir
dstdir=output/dir
# hg archive auto-adds a 'proj-version' prefix. Given the srcdir,
# proj-version/some/sub/dir/X should become dstdir/X, so strip 4 components
prefixlength=$(grep -c / <<<"/${srcdir%%/}/")
hg archive -t tar -I "$srcdir" - |
tar -xv -C "$dstdir" --strip-components=$prefixlength
You can
hg archive ... && cd output/some/sub/dir && tar ... isn't it?
Build intermediate repo (Convert Extension), where some/sub/dir/ will be root of this repository (understand also sample from Converting from Mercurial topic) and get tar'red archive directly from hg archive for intermediate repository

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

I am failing to commit to mercurial repo

I tried committing to a local hg repo and it refuses:
trouble committing plot.py!
note: commit message saved in .hg/last-message.txt
abort: Permission denied: /home/md/md_perf/.hg/store/data/plot.py.i
Your file permissions are messed up inside the local repository -- probably someone else pushed or committed to that repository without making sure they were leaving the permissions in a state usable by your whole group. Try these, with the appropriate substitutions, and sudo if necessary:
chgrp -R yourgroup /home/md/md_perf
chmod -R g+rwX /home/md/md_perf
find /home/md/md_perf -type d -print0 | xargs -0 chmod g+s

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.