Mercurial how to create patch for one file in repo - mercurial

I have a file called some/work/file.py in my repo.
I have been working in the repo (on other files too besides file.py) and committing my changes and have gone from revision 20 to 30.
How would I create a patch for only file.py from revisions 20 to 30 without including the other files?
Something like:
hg export 20:30 file.py > new.patch
Have tried the command but does not work.
Thank you

hg export exports individual changesets as separate entities.
If I understand you correctly, you need an answer to the question “What changes were made to file.c between revision 20 and revision 30?”, i.e. you need only need one diff file.
Here’s how you can do it:
hg diff file.c -r 20:30 > new.diff
As a more versatile approach, you can use -I (include file pattern) / -X (exclude).

Related

hg export-like output with all changesets between two revisions collapsed into one?

So, there is a project that I forked, and then I worked on it in my own branch, and pushed to my own fork. So let's say the last/tip of the original project was revision 5000; when I started working in my branch I made revision 5001, and now at the end, my branch tip is at revision 5050.
Now, if I use
hg export 5001:5050
... I get all the changesets in a single patch, which is however signed. This is great, but it makes reading for review difficult.
If i use:
hg diff -r 5000:5050
... or just hg diff -r 5000, I get all of the changes from all the changesets "collapsed" or "compressed" into a single changeset - this is great for reading for review, but does not include any signing, as in:
# HG changeset patch
# User username <user#e.mail>
# Date 1545633736 -3600
# Mon Dec 24 07:42:16 2018 +0100
...
... and does not include binary files, like hg export --git does.
So, is it possible to get an output like hg export --git R1+1:R2 (which includes signatures and binary files) - however, where all changes are collapsed like in hg diff -r R1:R2?
Note that I just want to generate a patch file, I do not want to mess with the history neither in my local copy of the fork, nor with the fork on the server - I mention this because I've seen With Mercurial, how can I "compress" a series of changesets into one before pushing?, and a lot of answers there talk about history rewriting and such...
EDIT: sort of got this with running these two commands in bash:
hg export | head -9 > ../mybranch.5050.patch
hg diff --git -r 5000 >> ../mybranch.5050.patch
... however, clearly the hg export header will be wrong, so I'd bet hg import will refuse it... So it would still be nice to know, if there is a way to get something like this, that hg import would accept...

Patch the move of an image on Mercurial

In my project, I've an PNG file and I want to move it on another directory.
I've done
mv f.png foo/f.png
hg addremove
hg diff > patch.diff
But I get this in my patch :
diff -r f0a573ab03b1 Bundles/rc/f.png
Binary file Bundles/rc/f.png has changed
diff -r f0a573ab03b1 Bundles/media/rc/f.png
Binary file Bundles/media/rc/f.png has changed
So when I apply it, it doesn't work... Is there someone who can help me ?
First of all, you should use hg mv instead of mv. That way, Mercurial knows that you renamed the file. When you use addremove, you pollute your history with a file delete and then a file add.
The next problem is the patch. The patch format doesn't support binary files. There is no way to create a patch for images.
Try hg export --git instead of hg diff. See this question: Why are my dlls not included in my exported patches?
hg export and hg import know how to handle all kinds of corner cases (like preserving your commit messages).

Mecurial: "5 files removed". Which 5 files?

I just did a hg update, and:
sourcedir> hg update
20 files updated, 0 files merged, 5 files removed, 0 files unresolved
hg removed 5 files. Which 5 files? Was there a command I could have typed to preview the update?
Once you hg update, it means you applied the latest pulled changes to your working directory.
Before update (and before pull), you can preview the upcoming changesets with an hg incoming command that will give you a preview of the changesets you are about to pull.
Also, a quick way to see what was done is simply be looking at the log: hg log.
I also strongly suggest you read the manuals and get more familiar with mercurial and its workflows.
I hope this helps.
You need to know how many revisions ahead you have updated. If your directory was 3 revisions behind its current state, you can find out the details with hg log -v -l 3. The -l 3 limits the length of the report to 3, and the -v lists the affected files with each changeset.

Can Mercurial be made to preserve file permissions?

I've seen a number of blog posts, and have experienced for myself, that Mercurial does not preserve the permissions on files pushed from one repo to another. Does anyone know of a Mercurial extension that would preserve the permissions? I'm assuming it can't be done with a hook, because what does a hook know about permissions at the originating repo?
Requested elaboration:
If the only change to a file is a change in permissions (e.g., chmod o+r filename), attempts to commit the file fail with a message saying that the file has not changed.
If I commit a file with permissions 600 (rw-------), then clone the repo, the same file in the clone has permissions 664 (rw-rw-r--):
: nr#yorkie 6522 ; hg clone one two
updating working directory
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
: nr#yorkie 6523 ; ls -l one two
one:
total 4
-rw------- 1 nr nr 8 Aug 18 21:50 foo
two:
total 4
-rw-rw-r-- 1 nr nr 8 Aug 18 21:51 foo
This examples shows that hg clone does not preserve permissions, but hg push does not preserve them either.
In my application, one repo is on a publically accessible path, and it's of major importance that
Multiple users have the right to change the repo
Files in the public repo become readable only when explicitly made readable.
It looks like it can be done using hooks and an auxiliary tool (and a little chewing gum and baling wire):
Get David Hardeman's Metastore, which saves and restores file metadata.
Alter the sources so it will ignore directory .hg as well as .git.
Use the following Mercurial hooks:
precommit.meta = metastore -s
changegroup.update = hg update
update.meta = /usr/unsup/nr/bin/metastore -a
You have to add the .metadata file to the repo.
This lashup will work most of the time, but if you change only permissions and want to propagate it, you'll have to run metastore -s in order to push those changes into the .metadata file where hg will see the change; otherwise the commit thinks nothing is new.
What about using this solution from the Mercurial FAQ:
If you're using Mercurial for config
file management, you might want to
track file properties (ownership and
permissions) too. Mercurial only
tracks the executable bit of each
file.
Here is an example of how to save the
properties along with the files (works
on Linux if you've the acl package
installed):
# cd /etc && getfacl -R . >/tmp/acl.$$ && mv /tmp/acl.$$ .acl
# hg commit
This is far from perfect, but you get the idea. For a more sophisticated solution, check out etckeeper.
For the specific case of the /etc directory, etckeeper looks interesting.
I assumed that metastore was abandonware due to the dead git link on author's site so I whipped the below which is placed directly in repo's .hc/hgrc configuration file:
[paths]
default = ...
[hooks]
# NOTE: precommit is different than pre-commit, see https://www.mercurial-scm.org/repo/hg/help/hgrc for list of hooks
pre-commit =
# export permissions
hg st -camn0 | sort -z | xargs -0 getfacl > .hg.hook.pre-commit.acl.export
hg add .hg.hook.pre-commit.acl.export
# export timestamps
hg st -camn0 | sort -z | xargs -0 stat > .hg.hook.pre-commit.stat.export
hg add .hg.hook.pre-commit.stat.export
update =
# import permissions
setfacl --restore=.hg.hook.pre-commit.acl.export
# import timestamps
# TODO: use touch to restore timestamps
It is not good idea to store permissions in VCS. However, Mercurial supports "executable" flag (that is not the same as permissions, although in Unix executable flag is part of permissions).

How can I recover a removed file in Mercurial (if at all)?

Accidentally, by using a GUI as opposed to CLI, I removed every file in a Mercurial project.
I recovered with Revert ok and lost some work, which as I have time machine I could easily get back. But is there a way of un-remove/undelete such files? Trawled through the manual and googled but cannot see anything. Any plugins?
I am probably answering my own question here but the files were gone from the directory and were not in the trash to recover so I am assuming Remove is irrevocable?
p.s. I know that hg forget or hg remove -Af will remove without deleting from the directory but my question has to do with the error I made as opposed to cool thinking the action through.
First, use hg grep to find the deleted file you wish to recover. The output of this command will show you the last revision for which the file was present, and the path to the deleted file.
Second, run hg revert -r <revision number> <path to deleted file>
The deleted file will now be in your working copy, ready to be committed back into head.
Quote from comment:
I set up a repository, committed all, Removed and then committed again
If this is the case then you just need to update the working directory to the previous revision:
$ hg update -C -r-2
Note the negative revision number. If the files you deleted aren't in the previous revision, you can find them by using:
$ hg log -v
For Mercurial 1.6 and above
If you know the name of the delete file you can find its revision easily with:
hg log -r "removes('NAME.c')"
This will give you the revision in witch a file called NAME.c (in the root) is deleted.
Then you can revert the file to the previous revision with (like other answers):
hg revert -r <revision number> <path to deleted file>
You can use a file name pattern instead to adapt to what you know, for example you can use **/NAME.c to search in all directories. You can read about it in File Name Patters. And use this link to know about the new revset specifications.
Well this worked for me.
hg revert -r revision pathToTheFile
An addition to the accepted answer - this is faster if you want to undo all removals in a commit. I deleted a large folder with a few hundred files in it and did hg addremove, which was not at all my intent, so had to undo all of those deletes.
Using Find deleted files in Mercurial repository history, quickly? + xargs + tr, revert all revision -3 removals to the version from revision -4:
hg log -r -3 --template "{rev}: {file_dels}\n" | tr ' ' '\n' | xargs hg revert -r -4
Note that this will fail if any of your files have spaces in the name; http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html doesn't appear to have any templates where {file_dels} is split by \n at the moment.
You can undo the last commit on a repo with hg rollback. There's only one level of rollback available, so if you did the remove with more than one commit, this won't completely undo your change. This only works on your local repository, so if you've pushed you won't be able to undo it in the remote repo.
You can remove committed revisions using the hg strip command, which is provided by the mq (Mercurial Queues) extension. This should give you back your files.
Make a backup before trying that out, because it will alter Mercurial's database of changesets.
The following worked for me.
hg revert -r <Revision Number> <File Name>
(Optional, to revert all files)
hg revert -r <Revision Number> --all
The below method is straightforward and so stupid that it cannot go wrong.
If you have deleted or renamed multiple files, it will be ok.
hg clone mydirectory mydirectory1
and now you start mc (or Far Manager) and compare what it was vs what it has become.
when it's done, just delete mydirectory1.