What SCM does support symlinks under Windows and Linux? - windows

I found out that subversion doesn't support symlinks under Windows.
I'm wondering if somebody knows a SCM tool that is able to work with symlinks under both Windows and Linux?
SCM tools currently missing symlink support under Windows:
Clear Case
Subversion
Mercurial
Perforce

Most SCM focus on storing normalized data (think of your SCM as a database). This means that they store source files and build scripts instead of storing executable files derived from them. People could store both but it leads to unnecessary duplication.
Similarly, symlinks are references to other files and represent a similar problem to data normalization.
Furthermore, pointers in general are hard to reason about. Adding support for pointers (symlinks) in a SCM means that certain operations will need to examine where the symlinks point and act accordingly. This makes merges harder, adding/updating symlinks is tricky because you need to figure out where it points (in repo vs. out of repo, two symlinks to same file, etc).
For these reasons, most VCS/SCM do not allow you to manage symlinks. Most SCM do have support for user defined hooks. Using custom hooks or other scripts to manage the symlinks is a better approach because it means the SCM doesn't have to reason about them (it's ignorant to them), and you are side-stepping the issue of data normalization that they create.
So, in conclusion, you're best off writing scripts that manages your symlinks and then calling those at the appropriate times (clone/checkout, update/commit, etc).

Git itself handles symlinks (symbolic links) natively; I mean here that Git stores information that file is symlink in repository.
I think that Git for Windows (msysGit) can represent symlinks in working directory on NTFS. There is also core.symlinks configuration variable, that if false makes Git check out symbolic links are checked out as small plain files that contain the link text. Git will probe and set 'core.symlinks' false if appropriate when the repository is created (git clone or git init).

Related

Working in git with directories with the same name but different case in Windows

I want to pull from a git repo in Windows which has two directories, named Foo and foo. Both the folders have different contents.
As Windows is case insensitive and doesn't allow folders with same name but different case, how do I push to the git repo?
Short answer: You can’t do this easily.
By default, this is a restriction of the Windows subsystem. Unless you use lower level system calls, Windows cannot differ between different casing; so even if Git is able to keep track of the differences, it can’t communicate these difference to the file system.
As pointed out in the comments by phuclv, it is possible to reconfigure the Windows kernel to be case sensitive. In Windows 10, this even works for individual folders, so you could use this to add compatibility where you need it. However, the case sensitivity per folder is not inherited, so you will need to manually change this for the folders that Git creates which might be a bit bothersome and makes this mostly a workaround.
Instead, you could make the whole file system case-sensitive but that might have additional implications, so just be careful if you want to do that.
Also note that even if there is support for case-sensitive content on the lower level, most Windows applications, including built-in Windows tools, will probably not be able to work with this. So this will only allow you to work with these files from certain tools. My guess would for example that most GUI based Git tools simply won’t work here.
If you don’t want to make these modifications, then what you maybe also could do is create partial commits where you just add files to the correct folder (you need to rename it in-between to get the different casing). But that will be very impractical.
In my opinion, the best solution is to simply avoid using multiple files on folders with conflicting names. Even on case-sensitive systems, this will only make things more confusing. By avoiding this completely, you also make it easier for all other developers to interact with the project.
As a follow up to poke's answer, you need to split those directories apart into different names, or merge them correctly into one with the same name, depending on your needs of course. They can't have the same name other the case and have it work in Windows (in a clear and obvious manner anyway).
I accidentally ended up in this same boat. I'm not sure how, as I was using Windows the whole time, but at some point I changed the case on a directory in the repo and some files ended up remaining in a directory with the "old" name and some in one with the "new" name. On my Windows machine they were all under the new name, but I found this problem when I pulled the repo into Linux, and confirmed the split when I looked in my remote repo.
To fix this, I first cloned the to a separate location on my Windows machine. Doing so, all the files were there in one directory again, as apparently the two directories just get merged. I then renamed that problem directory to "temp", (using the TortoiseGit "rename" operation). Then, I cloned the repo to yet another location. At that point, the two directories were in fact split apart in Windows. I had a "temp", plus the directory with the "old" name.
As I really did want them in one directory (on all platforms!), I moved the files out of the old named directory into "temp", then deleted the "old" directory. Next, I renamed temp (using the TortoiseGit "rename" operation again) to the name I wanted everything within, committed and pushed again. Finally, I pulled the changes into my original repo (my Linux one) and checked what was on the remote. Everything was finally in agreement, so I deleted those temp clones and called it a day.

Relative file referencing with SVN on Windows

I have a project with a sizable codebase. Associated with that codebase is a large amount of documenation that needs to maintained at the same version as the source code and which also needs to be easily accessible from within the codebase. However when our build machine builds the codebase I do not want the length of our build process extended by having the build machine checking out hundreds of megabytes of development documentation which is not needed for the build.
If this was on Unix I could simply have a 'docs' directory at the peer level of the codebase's 'source' directory. Then individual projects in the source tree could reference documentation in the docs tree using symlinks, and when the build machine does a build it would just check out the source directory and so not waste time checking out the unneeded docs directory.
However using SVN on Windows I don't see any way to set this up in a sensible way at all since SVN doesn't support symbolic links on Windows, even though Windows has them.
The only workaround I've come up with so far is to create batch files in the source tree which use cmd.exe and a relative file reference to open the documentation files in the docs tree. It works, but for some reason I can't quite put my finger on it leaves a nasty taste in the mouth.
Can anyone think of a better way of achieving this?
After some research I think I have a solution using the externals property.
Firstly using the svn:external property to reference a directory in the same repository. Set this on trunk/Proj1 to create Proj1/Docs referencing the contents of DocsDir/Proj1Docs
../DocsDir/Proj1Docs Docs
This creates a disconnected child working copy inside Proj1/Docs which references /DocsDir/Proj1Docs. Proj1/docs must not previously exist as part of the outer working copy (which makes sense since that would make it part of two working copies at once). If you edit the contents of Proj1/Docs then executing svn status inside the 'parent' working copy will list the changes to the child working copy, but you have to commit the changes to the child copy separately. Which is not a big deal.
Secondly using the svn:external property to reference to a file in the same repository. Set this on trunk/Proj1 to create Proj1/Readme.txt which references DocsDir/Readme.txt.
../DocsDir/Readme.txt Readme.txt
In the case of a file reference the directory in which the referenced file is imported must already be part of the owning working copy. In this case no child working copy is created and if you edit the file it is commited seamlessly as part of the owning working copy.
In both cases the build machine can execute
svn checkout --ignore-externals <path>
to checkout our codebase without all the bulky documentation.
Can anyone see a problem with this strategy?

Sharing a file between multiple locations

We are currently using Subversion (on Windows) for our source control but we examine switching to Mercurial. One problem is that we use externals in our repositories to share single files between multiple sub-projects. If one version of such a file is edited, the changes are propagated to each other version in our check-out. Is there a way to achieve the same in Mercurial, i.e. the same file in multiple locations? On Unix, this may be possible using some kind of links. But how about Windows?
Mercurial has the Subrepository features which is a little bit like svn externals.
The Mercurial feature is a more complicated than external in my point of view, but you can achieve the same goal with it and it is more flexible.
You can even use Subversion or Git repository as subrepo in Mercurial, so depending on what you're doing now, you could reuse your actual externals repo without any changes.
Everything is well explained in the linked documentation to have a good start with this functionnality !
BTW, symbolic links also exists on Windows : NTFS Symbolic link

Tracking hard or symbolic links with mercurial on Windows

In a rather large project, I would like to put the same file (or folder) in different locations. When it is changed in one location, the changes should be propagated. In Subversion, I could use externals to achieve this behavior.
I tried to solve this by using hard links and symbolic links, but Mercurial seems to not track any of them. Instead, it commits the content of the files to its repository instead of the link property. When I clone the repository, the information is lost.
Is this a Windows-specific behavior of Mercurial or can't it track links at all? Is there another way to track a file that is accessible from different locations in Mercurial?
Mercurial can track symbolic links, but they look strange when checked out on Windows. What happens is that Mercurial creates a file with the link target as the file content. There is unfortunately no support for creating real symbolic links on Windows systems that support them, such as Windows Vista. The result of this is that you cannot use symbolic links in a repository that is supposed to be portable between both systems. Please see the discussion in Issue1825 for more on this feature.
The closest match for svn:externals is Mercurial subrepositories. Depending on how you used svn:externals, subrepos may or may not be what you want. Please see my answer to another question about subrepos for some advice. I wrote part of the code for subrepos and off the top of my head, I think mounting a subrepo several times in the same main repository sounds like a recipe for confusion. But maybe you can make it work — just be aware that subrepos are a tricky part of Mercurial.

Git Merging of Binary Files (in particular Xcode project files)

I've got an Xcode project under git and I've got a "experimental" branch off of my "master" branch. Both branches have diverged since the branch (so no fast-forwarding!), and I am merging "experimental" into my "master" branch.
I've setup a .gitattributes file to treat a particular Xcode file (project.pbxproj) as binary, as it should be treated as such. However, I'm not sure exactly how to merge it. I'm not sure what that particular file does, but if for example it handled which files were added to the project there's no way I can merge them, and therefore I'd have to manually add certain files back to the project (possibly not remembering them all). How do others handle this situation?
Also, I've read that you have to manually update binary files (obviously) or copy over different versions. However, once I'm into the merge process the file in my working copy is the "master" version. How can I access the "experimental" version? I can't check it out as it would disrupt the merging process.
Thanks for your time!
In general, for binary files, I recommend a copy-merge type of .gitattribute directive.
That is, I just copy the file coming from the remote end of a merge.
For .pbxproj files however, that may not be a good option, as described here.
Wrapping these files would only make the problem worse as far as I can tell - as you wold be completely unable to merge changes.
While you can merge project files in some cases, it's not something that you should
count on being able to do. The basic recommendation is to avoid editing the project files at the same time as someone else.
I like versionning projects files (like the ones for Eclipse), only if I know they are:
not modified that often (certainly not by each developers)
only using relative paths
no data specifics to one workstation
In short, if those files are not to be merged (or will only be trivial to merge), I want them in a VCS. In your case, that may not be so useful to have them in said VCS in the first place.
Note: as mentioned in the Git manual:
During the merge, the index holds three versions of each file. Each of these three "file stages" represents a different version of the file:
$ git show :1:file.txt # the file in a common ancestor of both branches
$ git show :2:file.txt # the version from HEAD.
$ git show :3:file.txt # the version from MERGE_HEAD

Resources