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.
Related
Background: Mercurial Topics
Mercurial has a nice feature call topics as part of the evolve extension. These act as temporary lightweight local branches, and are an integral part of the Heptapod workflow, ensuring nice interactions with Git (via hg-git) for example. They are enabled by include the following in your ~/.hgrc file (or per-repo in .hg/hgrc):
# ~/.hgrc
...
[extensions]
evolve =
topics =
As these are designed for local work, when you push, the topics are not pushed to the server (but become temporary branches in git with the Heptapod workflow).
Question
How can I clone a repo locally to get the topics in my clone?
Part of the answer is to set the source repo to non-publishing: (One should probably do this in the cloned repo to after cloning).
# source_repo/.hg/hgrc
[phases]
publish = false
This keeps the draft phase of the changesets that are part of the topics.
Update: With python==3.9.7, mercurial==6.0.1, and hg-evolve==10.4.1 or higher, this seems to be sufficient. As #Craig points out in the comments, the original issue might have been because I was making the first commit a topic, but this is no longer an issue.
MWE (Old... This seems to work now.)
mkdir a
cd a
touch A.txt
hg init
hg add A.txt
hg topic "A"
hg commit -m "Initial commit of A"
cat > .hg/hgrc <<EOF
[phases]
publish = false
EOF
cd ..
hg clone a b
Now in a, there is a topic A and the commit is in the draft phase (shown by orange colour in the output):
$ hg log -v
changeset: 0:62c4... # orange, indicating draft phase
tag: tip
topic: A
user: Michael <...>
date: Wed ...
files: A.txt
description:
Initial commit of A
while in b, everything is the same, including the draft phase, but no topic:
$ hg log -v
changeset: 0:62c4... # orange, indicating draft phase
tag: tip
user: Michael <...>
date: Wed ...
files: A.txt
description:
Initial commit of A
Consider this a workaround, perhaps, but it should work.
If you're just working locally, you don't actually have to clone. You could just make a full copy of the entire working folder (the folder which contains the .hg folder).
Copy it anywhere you want, then when you run Mercurial commands within that path it will behave exactly like it was cloned, except it won't see your original as the default publishing repo, but instead the same one as your original. You can obviously change this in the .hgrc file if you need to.
Depending on your needs, you might want to do an hg up null beforehand to clear all the local working files, which will speed up the copy for a large repo.
It seems like this was a localized bug. Making the source repo publishing seems to be enough.
# source_repo/.hg/hgrc
[phases]
publish = false
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...
I would like to have Mercurial list all tracked files in the repo that are supposed to be symlinks. I can get a list of tracked symlinks that are symlinks in the working copy with hg files "set:symlink()", but that doesn't capture the tracked symlinks that aren't symlinks in the working copy.
What I want instead is a command that looks at the tracked file's properties in the manifest and tells me if the symlink bit is set. I've tried to use hg manifest -v, which the documentation says will "print file permissions, symlink and executable bits". I've tried that, but the symlinks are indistinguishable from non-link files whose executable bit is set. I get lots of:
755 * path/to/file
If I try to use the leading markers (hg manifest -v | grep '755 *'), the files I want are listed, but I also get lots of false positives.
Background: Adding and committing symbolic links seems to work for us, but Mercurial is refusing to create the symlinks when someone else pulls those changesets. I understand why Mercurial is refusing: we run afoul of an undocumented rule. So now we end up with files where the symlinks are supposed to be, and the content of the file is the path to which the symlink is supposed to point. If I can get Mercurial to tell me which files are supposed to be symlinks, I can easily replace the files with the appropriate links.
Thank you!
Edit: In my repository, the symlinks had not been committed properly due to a bug in the client, which is why hg manifest -v wasn't showing the committed files as links.
I've learned a few things, and I wasn't asking the right question, but let's get the close-enough answer out of the way first:
hg manifest -v | grep ' # '
Caveat: I will guess that it's possible for manifest to put multiple symbols between the permissions number and the path, so ' # ' as the grep expression may not work perfectly if you have an exotic set of bits on a file. I needed the spaces around the # because our repository has many files with # in their names.
The rest of the story: After some experimentation, I was able to determine that a particular mercurial GUI (SourceTree) wasn't committing new symlinks correctly, which turned out to be a longstanding issue with the Mac version. I created a new repo (hg init) and added/committed one target file and one symlink (Link\link.txt) with command-line hg. I then added/committed a second symlink (Link\STlink.txt) with SourceTree. hg manifest -v shows that the links were not treated the same by the different clients:
755 * Link/STlink.txt
644 # Link/link.txt
644 Target/target.txt
If I clone that repo, even with SourceTree, the Link/link.txt symlink is reproduced faithfully, but the Link\STlink.txt link is not. So the real fix for me is to replace all of the files with links and commit again from the command line and to try to remember not to use SourceTree to commit new symlinks again in the future.
To assess which files changed from symlink to 'normal files', you could try to throw some bash at it and compare the output of the fileset of the modified and unmodified versions. Maybe something like
diff <(hg files "set:symlink()" -r.) <(hg files "set:symlink()")
Example:
In a repository where eeg-link was added, foo22-link changed to a normal file and foo edited (and foo-link kept pointing at it):
$ hg diff
diff --git a/eeg-link b/eeg-link
new file mode 120000
--- /dev/null
+++ b/eeg-link
## -0,0 +1,1 ##
+eeg
\ No newline at end of file
diff --git a/foo b/foo
--- a/foo
+++ b/foo
## -1,2 +1,3 ##
foo is boo!
And this change, too!
+And even this.
diff --git a/foo22-link b/foo22-link
old mode 120000
new mode 100644
--- a/foo22-link
+++ b/foo22-link
## -1,1 +1,1 ##
-foo22
\ No newline at end of file
+This is no symlink anymore
we get a nice and clean output of
$ diff <(hg files "set:symlink()" -r.) <(hg files "set:symlink()")
0a1
> eeg-link
2d2
< foo22-link
showing the newly-added symlinks (eeg-link) and the removed symlink (foo22-link).
I can get a list of tracked symlinks that are symlinks in the working copy with hg files "set:symlink()", but that doesn't capture the tracked symlinks that aren't symlinks in the working copy.
In case it’s not clear from the other answers, the basic answer to the question is (ignoring any complications induced by bugs outside of Mercurial’s control) to add the -r option to hg files, e,g,
hg -r tip files 'set:symlink()'
Take this repo structure:
Server (main repo)
ProjectA (subrepo)
SharedLibrary (subrepo)
Client (main repo)
ProjectB (subrepo)
SharedLibrary (subrepo)
SharedLibrary points to the same folder (this is Windows), it is not a separate copy/clone under each main repo.
Assume each main repo has two changesets, 0 and 1(tip). We start with both main repos at the 1(tip) revision.
Take the following steps:
In the Client repo, update to changeset 0. This updates ProjectB and SharedLibrary to earlier but matching revisions.
ProjectA is now out of sync with SharedLibrary. Step 1 updated SharedLibrary to an older revision than what is required for ProjectA, which is still at 1(tip).
In the Server repo, we want to update SharedLibrary to the correct revision for ProjectA, so we run hg update tip in the Server main repo. This does NOT update SharedLibrary to the correct revision. It leaves SharedLibrary in the same revision as step one.
Go back to Client repo and run hg update tip. SharedLibrary is now at the correct revision for both ProjectA and ProjectB.
It appears updating in the Server repo isn't checking to see if SharedLibrary is at the correct revision. Is this behavior expected, or is there a better way to do this?
What you're seeing is that hg update will merge when the working copy is dirty. Let me explain it with a normal file first. Imagine you have a repository with two revisions. I'm at revision 0 and foo is modified:
$ hg diff
diff --git a/foo b/foo
--- a/foo
+++ b/foo
## -1,3 +1,3 ##
first
second
-third
+third line
You see I changed the third line. Now, if I run hg update 1 the modification will be merged with how foo looks like in revision 1:
$ hg update 1
merging foo
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
The modification is still there and foo is still dirty:
$ hg diff
diff --git a/foo b/foo
--- a/foo
+++ b/foo
## -1,3 +1,3 ##
first line
second
-third
+third line
When you did
$ cd client
$ hg update 0
you made sure that SharedLibrary was updated to the revision described in .hgsubstate for revision 0 in client.
When you then went to server, the SharedLibrary subrepo was no longer at the revision mentioned in .hgsubstate at revision 1 in server. In other words, the working copy in server was dirty — a hg commit would result in a new .hgsubstate file being committed.
Mercurial preserves this modification when you hg update in server and this is why you see that SharedLibrary wasn't made current when you updated. Use hg update -C if you want to make the subrepo current.
The idea behind this feature is that you can test different versions of your subrepos. When hunting for a bug, it's often necessary to update the main repository to older versions and so it's convenient that the modifications to the subrepo revisions stay in place.
Note that the confusing situation you're seeing isn't caused by how you've re-used the same subrepo twice. However, as Lasse points out, the real way to use a single subrepo in multiple projects is to put it once on your server and then clone it into your local clones — once per clone.
I've described this in more detail, but briefly you should follow the recommendations and maintain an identical structure on both server and clients. Use SharedLibrary = SharedLibrary paths in your .hgsub file to maintain this structure. Link the repositories together on the server-side (see my other answer) to make a single repository appear under several different URLs/directories.
When starting out with subrepos, then beware of tight coupling. If you can, then try to use a proper dependency management system such as Maven+Nexus for Java based projects.
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!