Mercurial - Check sanity patch - mercurial

I'm using Mercurial and I have a diff thanks to this command : hg diff
Here's my diff (example) :
diff -r 17899716342e config.js
--- a/config.js Sat Mar 17 14:01:53 2012 +0100
+++ b/config.js Sat Mar 17 18:15:16 2012 +0100
## -8,6 +8,6 ##
];
config.hostname = 'localhost';
-config.port = '3000';
+config.port = '8080';
-module.exports = canfig;
+module.exports = config;
In another repository, I would like to test is this diff can be applied. I know that hg import can import the diff in my current repository.
From the man :
-f --force skip check for outstanding uncommitted changes
--no-commit don't commit, just update the working directory
--bypass apply patch without touching the working
directory
But there's no argument to just check if the patch can be applied without modify my repository (and my working tree).
How can I do that ?

I suggest making a local throw-away clone and apply the patch to it if you don't want to modify your current working directory or repository. I don't think there is a way to do it otherwise.
With extensions you could shelve current changes, apply patch, update clean back to original parent, unshelve changes. Cloning seems simpler.

I like #Mark Tolonen's answer the most -- in Mercurial a new local clone is nearly instantaneous and takes up almost no space due to the use of hard links.
However, if you just can't abide doing so then use the --no-commit option and then revert.
hg import --no-commit the.diff # check if that succeeds or fails
hg revert --all # undo the attempted import

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...

Add a parent to the original changeset in Mercurial

I have a project with 24 months of source control history in a Mercurial repository.
I've recently found some old tarballs of the project that predate source control, and i think they would be useful to import into the repository as "pre-historic" changesets.
Can i somehow add a parent to my initial commit?
Alternatively, is it possible to re-play my entire repository history on top of the tarballs, preserving all metadata (timestamps etc)?
Is it possible to have the new parent commits use the timestamps of these old tarballs?
You can use the convert extension to build a new repository where the tarballs are imported as revisions before your current root revision.
First, you import the tarballs based on the null revision:
$ hg update null
$ tar -xvzf backup-2010.tar.gz
$ hg addremove
$ hg commit -m 'Version from 2010'
$ rm -r *
$ tar -xvzf backup-2011.tar.gz
$ hg addremove
$ hg commit -m 'Version from 2011'
I'm using addremove above to give Mercurial a chance to detect renames between each tarball (look at the --similarity flag to fine-tune this and use hg rename --after by hand to help Mercurial further). Also, I remove all the files in the working copy before importing a new tarball: that way the next commit will contain exactly the snapshot present in the tarball you unpack.
After you've imported all the tarballs like above, you have a parallel history in your repository:
[c1] --- [c2] --- [c3] ... [cN]
[t1] --- [t2] --- [tM]
Your old commits are c1 to cN and the commits from the tarballs are t1 to tM. At the moment they share no history — it's as if you used hg pull -f to pull an unrelated repository into the current one.
The convert extension can now be used to do a Mercurial to Mercurial conversion where you rewrite the parent revision of c1 to be tM. Use the --splicemap flag for this. It needs a file with
<full changeset hash for c1> <full changeset hash for tM>
Use hg log --template '{node} ' -r c1 -r tM > splicemap to generate such a file. Then run
$ hg convert --splicemap splicemap . spliced
to generate a new repository spliced with the combined history. The repository is new, so you need to get everybody to re-clone it.
This technique is similar to using hg rebase as suggested by Kindread. The difference is that convert wont try to merge anything: it simply rewrites the parent pointer in c1 to be tM. Since there is no merging involved, this cannot fails with weird merge conflicts.
You should look at using rebase. This can allow you to make the changes the 2nd changeset on your repo ( you have to rebase from the 1st ).
https://www.mercurial-scm.org/wiki/RebaseExtension
However, note that if there are other clones of this repo existing ( such as for fellow developers, or on a repo server ), you will have issues with them pulling the revised repo. You will probably have to co-ordinate with the owners of those clone's to get all work into a single clone, rebase that clone, and then have everyone re-clone from the revised clone. You will also have to change the phase the of the changesets.
https://www.mercurial-scm.org/wiki/Phases
Honestly though, I would just add them to your 'modern-day' repo, I don't think making them pre-historic would give you any notable advantage over adding them to the top.

Freshly cloned hg repository shows files as modified (Windows)

I've freshly cloned a Hg repository on Windows XP and hg status reports a lot of (all?) files as Modified. What could be the reason?
E:\myprojects\myproject>hg summary
parent: 206:03856faec803 tip
latest commit message
branch: default
commit: 78 modified
update: (current)
Even after having performed hg revert --all --no-backup, hg diff --git reports:
diff --git a/path/to/file1 b/path/to/file1
--- a/path/to/file1
+++ b/path/to/file1
## -1,332 +1,332 ##
-line1
-line2
...
-line332
+line1
+line2
...
+line332
diff --git a/path/to/file2 b/path/to/file2
--- a/path/to/file2
+++ b/path/to/file2
## -1,231 +1,231 ##
...
line231
\ No newline at end of file
If hg revert isn't able to restore a clean working directory, this most likely means that the repository doesn't contain the files in canonical form, but hg status gets them into canonical form before comparing against the repository contents. Usually this happens when eol-extension is turned on, but the repository contains files with CRLF. To be sure, turn eol-extension temporarily off and check whether the files are still modified. If so:
(1) turn it on again and commit the changes, so they will be in canonical form in the repository, too.
(2) make sure that other users accessing your repository have eol-extension turned on, otherwise this will be a never ending game :)
Try hg diff --git that will shows you what Mercurial thinks is modified about the files. My guess is the execute bit permission.

Find what mercurial commit changed the executable bit on a file

I know how to use hg blame to find what exact commit changed a line in a file, but I can't find a similar way to find when the executable bit on a file was changed.
First note that as changes in the exec bit don't affect the file contents, like deletions, they will not necessarily be shown by 'hg log filename'. (Unix nerds can compare the ctime/mtime rules for files and directories with respect to rm/chmod to understand this distinction.) So you will need to use something like:
$ hg log --deleted file
to show all changesets that touch a file, include exec changes, deletions, and duplicates. This is not enabled by default for various reasons including that it can be an order of magnitude slower.
Finding exec bits while perusing the log will also mean looking at git-style patches as standard patch(1)-compatible patches don't know about exec bits. So the total command might look something like:
$ hg log --removed -pg contrib/simplemerge | grep "^new mode" -B 10
+ import os
sys.exit(main(sys.argv))
changeset: 4363:2e3c54fb79a3
user: Alexis S. L. Carvalho <alexis#cecm.usp.br>
date: Mon Apr 16 20:17:39 2007 -0300
summary: actually port simplemerge to hg
diff --git a/contrib/simplemerge b/contrib/simplemerge
old mode 100644
new mode 100755
That reads: "search all git patches on simplemerge for lines starting with 'new mode' and show the previous 10 lines".
Another alternative is to use bisect. This can be used for finding basically any sort of change you can test for. For instance, if you're looking for where the X bit is set:
$ hg bisect -g 1000 # some past revision without the X bit
$ hg bisect -b tip # some recent revision with the X bit
Testing changeset 8114:ad3ba2de2cba (14179 changesets remaining, ~13 tests)
993 files updated, 0 files merged, 716 files removed, 0 files unresolved
$ hg bisect -c "[ ! -x contrib/simplemerge ]" # shell expression returns 0 (good) if no x bit
Changeset 8114:ad3ba2de2cba: bad
Changeset 4566:087b3ae4f08a: bad
Changeset 2797:a3c6e7888abf: good
Changeset 3678:7e622c9a9707: good
Changeset 4121:d250076824e3: good
Changeset 4345:ec64f263e49a: good
Changeset 4454:28778dc77a4b: bad
Changeset 4403:15289406f89c: bad
Changeset 4371:d7ad1e42a368: bad
Changeset 4355:10edaed7f909: good
Changeset 4366:390d110a57b8: bad
Changeset 4363:2e3c54fb79a3: bad
Changeset 4361:99c853a1408c: good
Changeset 4362:465b9ea02868: good
The first bad revision is:
changeset: 4363:2e3c54fb79a3
user: Alexis S. L. Carvalho <alexis#cecm.usp.br>
date: Mon Apr 16 20:17:39 2007 -0300
summary: actually port simplemerge to hg
Here we've automated the test with a standard Bourne shell expression to check a file's exec bit and Mercurial then runs through checking out revisions and testing them for us.
There may not be a simple build-in method a la hg blame (or maybe there is, and I just don't know it!), but you should be able to use a brute-force approach to hunt down the changeset by looking at the diffs.
First, you need to enable git-style diffs, because hg's normal diff output does not show changes in file modes. To do this, add to your hgrc the following:
[diff]
git = True
Then, you can look at all the diffs for the file you're interested in and find the commit that changed the mode, by running:
hg log -p file_of_interest
If you're on a *nix system, it helps to pipe to less or grep to easily search through the output. The mode changes should be displayed just below the beginning of the patch line that starts with:
diff --git a/file_of_interest b/file_of_interest
old mode ....
new mode ....
So, for instance, you might be looking for a mode change from 644 (no exec) to 755 (exec bit set), in which case you'd see something like:
old mode 100644
new mode 100755
Once you find the diff you're after that contains the mode change you're after, you can search backwards to get the commit hash.
Not quite as simple as hg blame, but it should work to some degree. Hope that helps.

No changes are pushed when using hg-git

I'm trying to get the hg-git extension working under Windows and after hours of fiddling, I finally seem to have it working. However, nothing shows up in my git repository even though the output of hg push reads:
importing Hg objects into Git
creating and sending data
github::refs/heads/master => GIT:8d946209
[command completed successfully Wed Oct 20 15:26:47 2010]
Try issuing the command hg bookmark -f master
(use -f to force an existing bookmark to move)
Then try pushing again.
This works because Hg-Git pushes your bookmarks up to the Git server as branches and will pull Git branches down and set them up as bookmarks. (from the official README.md)
And it seems that just after I asked this, I made a trivial change. This was picked up and pushed. So it seems that you have to wait until you've made a new commit in order for hg-git to pick it up.
I had chosen to 'Initialize this repository with a README'. This meant I ended up with two heads, which I couldn't hg merge because one had a bookmark.
To get pushing working, I had to:
configure hg-git and github remote as per https://blog.glyphobet.net/essay/2029
pull from github and update
force the merge (checking which id to use with hg heads),
commit the merge
add a trivial change to a file (add a space char to the end),
commit, then
move the bookmark to the tip
push to my configured github remote
This ended up with commands as follows (substituting in <x> sections)
hg pull github
hg update
hg merge <revision-id-of-incoming-git-version>
hg addremove
hg commit -m 'merged with github'
# make some trivial change to a file - eg add a space where it doesn't cause harm
hg add <changed-file>
hg commit -m 'trivial change'
hg bookmark -f master
hg push github
make sure you pick the remote revision for the merge above - if you don't it doesn't work!