Adding symlink to repository on windows - mercurial

Mercurial allows versioning symlinks in a repository. On unix they are created as symlinks on checkout while on windows symlinks are not supported.
Instead Mercurial apparently creates a "special" text-file for each symlink with its content being the target of the symlink. By modifying the content of this text file on a windows machine, one can change the target of the "symlink". (See this SO answer.)
Is it similarly possible to create a new symlink in a Mercurial repository on a Windows machine?
I imagine this would involve creating the "special text" file and then somehow telling mercurial to treat it as a symlink. Possibly with a workaround similar to this workaround for setting the executable bit.

I don't have a Mercurial installation on Windows to try this, but using hg import (possibly hg import --no-commit) for the following file seems to work on OS X and should work on Windows:
diff --git a/link b/link
new file mode 120000
--- /dev/null
+++ b/link
## -0,0 +1,1 ##
+other/file
\ No newline at end of file
Replace link with the name of the file that's supposed to be the symlink and other/file with the name of the file that it is to link to.
Note that the last line is important; it prevents a newline from being added to the end of the path.

Related

How can I get Mercurial to list all tracked files that are tracked as symlinks?

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()'

Detect is file is versioned

For example I have a hg versioned project in this path: C:\src\sample_project
Now, lets this project have subfolders, and lets say I'm editing a file inside this project C:\src\sample_project\docs\index.rst.
Having the path of this file C:\src\sample_project\docs\index.rst what is the easiest and most effective way to check if the file is versioned by hg, by either using Windows shell commands, hg.exe or tortoise (thg.exe)?
I'll post my doubt as answer.
Command to check if file is versioned: hg status <path> and then if the first character in stdout of this command is ? or a (from abort: no repository found in...) I should assume that file is not versioned.
What you stated is a way, but there is a cleaner one imo. You can use:
hg status -u which lists all unknown (read: not tracked) files in your repository.

Why are my dlls not included in my exported patches?

I have used TortoiseHg to export a few changesets from a Mercurial repository.
This went fine, except that the SignalR dlls were not included in the patch of the changeset where I added those dlls.
Why are they not being included? If I look at the changeset on my machine, I can see the dlls are added in the changeset.
How can I add these dlls to the patch!?
I installed SignalR through nuget.
Thanks in advance.
EDIT: I also noticed that another change to a file is also not included in the patch of that changeset.
EDIT: When I open the patch in notepad++, I saw mention of the files:
diff -r b10c68a2d387 -r 74aa5e71d315 MyProject/_sln/packages/SignalR.Server.0.5.3/lib/net40/SignalR.dll
Binary file MyProject/_sln/packages/SignalR.Server.0.5.3/lib/net40/SignalR.dll has changed
It looks like you're not passing the --git option to hg export. Without --git hg export will not include changes to binary files (or permissions, etc).
Personally, I think this should be the default now for everything that produces a diff in some form, but it's still not.
File -> Settings

How to prevent ignored files from being removed?

I version controlled a project settings folder a couple months back on my default branch, and then over time created many branches off default. Now I've decided that I'd rather not have the project settings folder version controlled as it creates a lot of problems when switching between branches.
So I've hg forget'd this project settings folder which lets me keep the files on my local machine but removes them mercurial. However, when switching from one of the old branches which still have this folder versioned back to the default branch it actually removes the files from the local machine, which is bad.
How do I prevent that?
The folder is also in .hgignore on default now.
It's impossible to do.
But the common practice is to keep config.ini.dist in your repository and build environment-specific config by some build-system right after you check source code out.
The standard way to deal with this is to version control a template config file and ignore the real config file. The real config file can then include the template file, or maybe the template file is copied over once in a while.
The underlying reason for your problems is that running:
$ hg forget config.ini
is exactly the same as running:
$ hg remove config.ini
$ hg cat config.ini > config.ini
The forget command leaves the file behind in your working directory, but what you commit is still a file removal. This means that afterwards, Mercurial cannot distinguish between "file was forgotten" and "file was removed" — only the removal is committed, so the two commands look exactly the same.

Mercurial convert changes line endings?

I'm using the Mercurial Convert extension to import data from a PerForce repository. The conversion appears to have worked correctly, but all the Windows line endings (CRLF) were replaced by unix endings (LF).
Is there a way to get this extension to leave the line endings alone?
While the conversion itself may change the eol style, you still can, in your new Hg repo, specify what eol you want to see for certain types of files on checkout:
See EolExtension.
When working with people on different operating systems, it can therefore be desirable to be able to checkout text files with the operating system native line ending representation.
This extension lets you specify how end of lines (EOLs) are converted between the repository representation and the working copy representation.
I was able to do what I wanted using the "Perfarce" extension for Mercurial. The line endings for the mercurial repository will follow the settings of the "LineEnd" property of the Perforce workspace you are using. The steps were the following (on Windows):
Clone the Perfarce repository (https://www.mercurial-scm.org/wiki/PerfarceExtension)
In the mercurial.ini file of your user folder, add the configuration information described https://www.mercurial-scm.org/wiki/PerfarceExtension
Create a Perforce workspace that maps desired parts of the Perforce repository to the root folder for the workspace on the local computer
Update the local workspace
Open a command line at the parent folder of the desired mercurial repository folder
set P4PASSWD=your_perforce_password
set P4USER=your_perforce_username
hg clone p4://perforce_server_ip:perforce_server_port/your_perforce_workspace_name destination_folder
The resulting hgrc file for this repository is set up to pull additional changes from the Perforce repository, so it could conceivably be used on an ongoing basis, but I didn't use that.