Search code examples
windowsgitjenkinscygwinsymlink

How to use symlinks created by Windows git with Cygwin


I am using Jenkins on a Windows machine to build a Cygwin program. Recently that started to fail.

I turned out that was because Windows' git seems to represent symbolic links in the repo as plain text files.

There are two possible approaches to solve this:

  1. Use Cygwin's git to do the checkout.
  2. Convert the links (a.k.a. plain text files) to Cygwin links

The first turned out to be not as simple as I wished, pointing to Cygwin's git.exe was not enough as we need the cygwin1.dll in the path. This and some other issues made me abandon this apporach. I'm interested in suggestions on how to do that, in essence turning a Windows Jenkins into a Cygwin Jenkins.

However, turning Windows git "links" into Cygwin links seemed feasable. What would be a simple way to do that and could be run as an initial step in the Jenkins build?


Solution

  • I wrote a simple bash script to find all the "links", easy since they are marked with flags 120000 according to this answer. Then it was a simple matter to just pick up the target filename (the content of the text file) and then replace the file with a symbolic link.

    Since it is a bash script it can easily be used from Cygwin and MSys.

    #!/bin/bash
    #
    # https://stackoverflow.com/a/38140374/204658
    #
    # Script to convert symbolic links created by a windows git
    # clone/checkout to cygwin links. When a typical Windows git checks
    # out a symbolic link from the repo it (MsysGit, at least) tend to
    # produce text files with flag 120000 and the link target file name as
    # the content.  Strategy would simply be to find all those and replace
    # by cygwin links.
    #
    # This will work if you are not planning on commiting anything, e.g.
    # in a Jenkins, or other CI, build environment
    
    for f in `git ls-files -s | awk '$1 == "120000" {print $4}'`
    do
        # echo $f is a symlink pointing to $dir/$target
        dir=$(dirname "${f}")
        pushd "$dir" 2>&1 > /dev/null
        file=$(basename "$f")
        target=`cat "$file"`
        rm "$file"
        ln -s "$target" "$file"
        popd 2>&1 > /dev/null
    done