Git: unable to create symlink (File name too long)
Asked Answered
S

6

33

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)?

Subacute answered 23/8, 2013 at 20:20 Comment(1)
Sounds link you added the content of the text files, but git still handles it as links, and tries to handle your textfile-content as link-path. You should check if your mode for this files in git ins NOT 120000 (what should stand vfor symlinks) instead it should be e.g. 100644. Read the orginal post for more details about the symlink mode at stackoverflow.com/a/18791647Rotherham
O
16

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.

Othaothe answered 24/8, 2013 at 14:48 Comment(0)
H
36

Here's a solution that doesn't require you to go back and fix commits. After all it may not be feasible if the repo is remote or shared. It uses core.symlinks=false. You said you tried this but did not say when. You must do it before a checkout, which a normal clone does by default. So you must clone with the --no-checkout option.

git clone --no-checkout the-repo tmp-clone-dir
cd tmp-clone-dir
git config core.symlinks false
git checkout
cp the-problem-file the-problem-file.bak # make a backup
git rm the-problem-file
git commit -m 'Removed problem file pretending to be a symlink' the-problem-file
mv the-problem-file.bak the-problem-file # restore the backup; now it will be of type file
git commit -m 'Added back the problem file - now with the correct type' the-problem-file
git push origin master
cd ..
\rm -rf tmp-clone-dir  # IMPORTANT

That last step is important because you don't want to do more work in a repo with core.symlinks=false. It's just asking for trouble.

The above assumes that you want the file to be a file not a symlink. If it was meant to be a symlink then you'd stop after the first commit, remove the tmp-clone-dir and go back to your normal repo checkout to make the symlink and commit it.

The benefit in this method is that you don't break any related clones and branches as it preserves history. The downside to this is that the broken commit is still there and will cause problems for anyone if they attempt to use that particular bad commit.

Hexastich answered 25/10, 2014 at 2:1 Comment(4)
Plus 2 if I couldHaemolysis
This worked like a charm. It should be the accepted answer.Petepetechia
Had to use git add <problem file> before the second commit to work. Perfect answer!Imf
For me the simple clone of the local repo didn't work because afterwards the url for the remote "origin" points to the directory where git pull failed - the problematic commit isn't there. (Maybe changed in newer versions of Git?) Basically, I had to use: git clone --no-checkout --reference the-repo <CLONEURL> tmp-clone-dir (Using reference makes the clone faster.) Or you use the original command and just edit .git/config.Gremlin
F
19

I had this problem, this resolved it for me:

git config core.symlinks false
git rm <problem-file>
git commit <problem-file>
git push
git config core.symlinks true
Flannery answered 10/7, 2015 at 13:21 Comment(3)
Aren't you missing a checkout command after the first command?Cholent
Yes, this is probably the easiest solution. Temporarily disabling symlinks enables us to pull the problematic commit and it seems it only affects newly created files. It can become messy if you also pull commits that adds correct symlinks ... PS! The missing step is git pull, not git checkout.Gremlin
just git config core.symlinks false worked for meAnticlastic
O
16

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.

Othaothe answered 24/8, 2013 at 14:48 Comment(0)
Q
3

I had the same problem with a small number of files. I solved it by removing them from the repository using git remove --cached <file> which doesn't delete the files in my source (which are no longer symlinks). Once all are removed, git sees they're still there so I can add them back using git add . and then commit them back in. Now git sees them as normal files.

Quicksilver answered 15/5, 2019 at 21:48 Comment(1)
This worked perfectly but the command is git rm --cached <file>Aziza
I
0

git config --global core.longpaths true

Put this one and try again. It will work.

Indication answered 6/1, 2022 at 9:49 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Isoniazid
This should be the accepted answer. The problem isn't with the symlinks as much as it is with git not accepting long paths without this being set properly.Briant
J
-1

There is also an easier way if you are using bitbucket. Since now bitbucket supports online deleting of the files you can go to your repo on bitbucket, find the file that is problematic, press the dropdown button near "Edit" button and "Delete".

That will delete the file with broken symlink and you have a working directory again. if this is a possibility it is much faster than rebasing and deleting manually.

Jeffersonjeffery answered 23/7, 2015 at 8:53 Comment(2)
question is about git, not bitbucketIronclad
Downvoted because this "solution" can lead to data loss! You have not understood what the original question is about. He doesn't want to get rid of the symlinks entirely, instead he wants to convert the symlinks to normal files and preserve the contents of the files. If you delete the symlink you lose the contents and gain nothing in return.Province

© 2022 - 2024 — McMap. All rights reserved.