Saturday, 7 July 2012

msysgit & corrupted symbolic links

Using msysgit on Windows?

Let's say the project you are cloning has:

Where linked-directory-1/ is a symbolic link to real-directory-1/.

What you will find in your clone of this project is:
Where linked-directory-1 is a file containing the local path of what it's target would be if it were the symbolic link it were supposed to be.

The problem?

Cloning projects in a broken state just seemed.. ridiculously unusable.  I've wasted hours on errors that appear to be in one place, but are actually because of these broken symbolic links.  With a bit of googling, I encountered someone suggesting that someone else set their core.symlink GIT setting.  Out of curiosity, I decided to check the .git/config file in my cloned project.

        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
        hideDotFiles = dotGitOnly

I don't understand..  The default value is to create broken clones, with missing symlinks and junk files littered throughout them?  Is there something I am missing here?

The solution?

A bit of further searching revealed that you can set this setting globally.  Something like:
git config --global core.symlink true
After executing that, and then modifying the red highlighted project-specific setting..
$ git checkout -f
error: unable to create symlink AndroidAppSettings.cfg (Function not implemented)
error: unable to create symlink project/jni/application/atari800/atari800 (Function not implemented)
Now the files are missing, but at least I know that the clone is bad.

I think the best approach is to have it work this way by default, then cloned projects can have their local setting changed in their configuration file.  Then the corrupted clone can be processed with a script to turn the corrupt files into the links they should be.

The following almost does the trick:

git ls-files -s | awk '/120000/{print $4}' | while read FILEPATH
    if [ ! -e $FILEPATH ]; then
        echo "Please check that GIT core.symlink for this project is 'false'" 1>2
        exit 1

    if [ ! -L $FILEPATH ] && [ -f $FILEPATH ]; then
        wc -l $FILEPATH | while read LINES DISCARD
            if [ "$LINES" = "0" ]; then
                FILEDIR=`dirname $FILEPATH`
                FILENAME=`basename $FILEPATH`
                LINKPATH=`cat $FILEPATH`
                pushd . > /dev/null
                cd $FILEDIR
                if [ -e $FILENAME ]; then
                    if [ -e $LINKPATH ]; then
                        ln -s -f $LINKPATH $FILENAME
                        echo "Repairing symlink: $FILEPATH"
                        echo "$FILEPATH: symlink path '$LINKPATH' invalid" 1>2
                    echo "$FILEPATH: problem finding this file"
                popd > /dev/null
                # ERROR: Expected a file with one line for the link path
                echo "$FILEPATH: bad link file: expected 0 lines, got $LINES" > /dev/null # 1>2
        echo "$FILEPATH: already a symlink" > /dev/null # 1>2
What it does not do, is create a symbolic link within the same directory, to that same directory the link is intended to reside within.


Do not use Git for Windows AKA msysgit.  Even if you work around the corrupted files with the above script, you cannot make the links yourself because some cases are not supported by the ln command.  You can get a little further by switching over to a MinGW msys installation (the above script works in the "does not do" case), but there are still problems.  It is probable that MinGW ln is copying, rather than linking, given the time the script takes to run.

Cygwin has the same problem, when using it's git command.

Portable Ubuntu has been recommended, but I haven't tried it yet, or looked at it's suitability.

Next: Android NDK & Windows symbolic links.

No comments:

Post a Comment