简体   繁体   中英

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

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.

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

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 add ing 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.

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.

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.

git config --global core.longpaths true

Put this one and try again. It will work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM