Search code examples
gitbitbucketsymlink

Unable to create symlink (File name too long)


I had pushed a project from Linux to Bitbucket and then cloned it on Windows. Turns out there were two symlinks, which appeared as textfiles on Windows. Since I knew where they should point to, I replaced them by copies of their destination files, committed and pushed.

Now the Bitbucket repository looks okay when I look at it from their web interface. However a git clone on my Unix machine gives me two messages like:

error: unable to create symlink ... (File name too long)

and the two files, which were symlinks previously are absent. I tried cloning into /tmp/... to get shorter filenames, but got the same results. That suggests, that something went bad with the Bitbucket repository. I tried core.symlinks on and off.

I can live without the symlinks, but I'd like to have a working repository. Does anybody know a way (other than recreating the repository)?


Solution

  • As soon as you changed the content of a fake-symlink-file without also changing its mode from symlink to regular file and committed the result, you made a blob that can't be extracted on an OS with real symlinks, because you have an object that is supposed to be a symlink but its content is too long to be a pathname. The web interface is not doing you any favors by hiding this problem.

    You're probably going to have to back up to that commit, fix it, and re-commit everything after it. git rebase -i will help, but it still might not be easy, especially if you've made more changes to the files while they were in this bogus symlink-but-not-really-a-symlink state.

    Supposing that the bad commit is abcdef123, you need to do this:

    git rebase -i 'abcdef123^'
    

    which will put you in an editor with a list of commits. abcdef123 should be on the first line. On that line, change pick to edit. If there is more than one bad commit, change all of them to edit. Save and exit the editor.

    Now you'll be back in the point in time where you committed the bad file. This is your chance to alter history, putting things right that once went wrong. Inspect the commit with

    git show
    

    and undo the bad part by restoring the original symlink pathname into the file and git adding it. Or you could really get rid of the symlink properly with git rm, then create a new file and git add that. If you choose the first option, be aware that the content of a symlink is just a pathname. It's not a text file - it doesn't have a newline on the end. If you edit it with a text editor that adds a newline, you'll have a broken symlink (pointing to a file with a newline in its name).

    After you've done your git add, reinsert the fixed commit into its place in history:

    git commit --amend
    git rebase --continue
    

    If you changed multiple commits from pick to edit you'll have to repeat that procedure for each one. The final git rebase --continue will bring you back to the present.

    If you are at a past commit during the rebase and you discover that the whole commit is bad (it did nothing else besides replacing a symlink with the unmodified content of the file it points to), then you can git rebase --skip instead of amending and continuing. If you know ahead of time that this is going to happen, you can just delete the bad commit from the git rebase -i list instead of changing its pick to edit.

    If you have multiple branches affected by the bad commit(s), you will have to repeat the whole procedure for each branch. Check out a branch, run the git rebase -i to completion (which is when git rebase --continue says "Successfully rebased"), then check out the next branch and do it again.

    In the future, when splitting your development work between Windows and a real OS, do your Windows work with cygwin. Inside cygwin, symlinks are symlinks and you can't mess them up like you did.