Categories
git symlink version-control

How does Git handle symbolic links?

1918

If I have a file or directory that is a symbolic link and I commit it to a Git repository, what happens to it?

I would assume that it leaves it as a symbolic link until the file is deleted and then if you pull the file back from an old version it just creates a normal file.

What does it do when I delete the file it references? Does it just commit the dangling link?

8

  • 26

    .gitignore sees the symlink as a file not a folder.

    – 0xcaff

    Feb 3, 2014 at 15:34

  • 9

    Well, evidently there’s more to the question than that answer implies. For instance, I’m wondering the following: if I create a sym link in my repository to some large file in that repository, push the changes, and then pull those changes to another machine, what will happen? Will the large file be stored as a large file in both locations, or will the sym link be preserved, such that on the new machine, the link file points to the original large file?

    – jvriesem

    Jun 13, 2014 at 0:06

  • 8

    This is is an old thread but this comment may still be useful. In response to jviesem, a soft link is basically a file with the name of another file. So once you pull it to a different machine, the link will be downloaded and it will have the name of the big file on the original file system. If on the new machine the name isn’t valid, then then link will have a invalid name. The big file will not be downloaded to the new machine.

    – lasaro

    Nov 19, 2015 at 18:29

  • 9

    @lasaro, the way to avoid broken links in a git repo is to always use relative paths when making the symlinks, using ../.. as needed.

    – Wildcard

    Jan 22, 2016 at 23:57

  • 14

    Notice that in most versions of Windows you need elevated permissions in order to create a symlink. If you’re on Windows and git pull creates a file instead of symlink, try to run you Git client as administrator.

    – axmrnv

    May 30, 2017 at 11:04


1555

From linux symlink manual (assuming you are in Linux):

A symbolic link is a special type of file whose contents are a string that is the pathname of another file, the file to which the link refers. (The contents of a symbolic link can be read using readlink(2).)

So a symbolic link is one more file, just as a README.md or a Makefile. Git just stores the contents of the link (i.e. the aforementioned path of the file system object that it links to) in a ‘blob’ just like it would for any other file. It then stores the name, mode and type (including the fact that it is a symlink) in the tree object that represents its containing directory.

When you checkout a tree containing the link, it restores the object as a symlink regardless of whether the target file system object exists or not.

If you delete the file that the symlink references it doesn’t affect the Git-controlled symlink in any way. You will have a dangling reference. It is up to the user to either remove or change the link to point to something valid if needed.

8

  • 355

    BTW. If you are on filesystem like FAT that does not support symbolic links, and your repository uses them, you can set core.symlinks configuration variable to false, and symlinks would be checked out as small plain text files that contain the link text.

    Jun 5, 2009 at 9:42

  • 22

    @JakubNarębski I saw this before. There was a text file in our repo with one line, a path to a library we use. Couldn’t figure out what the purpose of it was. I know now what happened.

    – Matt K

    Apr 10, 2014 at 14:40

  • 44

    I hesitate to comment on highly upvoted answer but I think the phrasing “just like it would for a normal file” might be misleading to newcomers. It is like a normal file only in that the content is in a blob. The critical difference is that for a normal file the blob is the file content but for a symlink the blob has the pathname of the file it links to.

    Oct 25, 2014 at 2:55


  • 15

    @JakubNarębski Regarding “small plain text files” .. You would hope they are small and text but of course a blob is a blob and potentially could be huge and binary. See stackoverflow.com/questions/18411200/… for when a file is mistyped as a symlink.

    Oct 25, 2014 at 3:15


  • 7

    Be sure to check your global settings for symlinks and the local settings for symlinks. If settings were copied over from TortiseGit or windows, then you could have symlinks = false messing with them.

    – phyatt

    Dec 12, 2017 at 17:05

363

You can see what Git does with a symbolic link by adding it to the index. The index is like a pre-commit. When the index is committed, you can use git checkout to bring everything that was in the index back into the working directory. So, what does Git do when you add a symbolic link to the index?

First, make a symbolic link:

$ ln -s /path/referenced/by/symlink symlink

Git doesn’t know about this file yet. git ls-files lets you inspect your index (-s prints stat-like output):

$ git ls-files -s ./symlink
[nothing]

Now, add the symbolic link to the index. When you add a file to the index, Git copies its contents in the object store.

$ git add ./symlink

So, what was added?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink

The hash is a reference to the packed object that was created in the object store. You can examine this object if you look in .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c in the root of your repository. This is the file that Git stores in the repository, that you can later check out. If you examine this file, you’ll see it is very small. It does not store the contents of the linked file. To confirm this, print the contents of the packed repository object with git cat-file:

$ git cat-file -p 1596f9db1b9610f238b78dd168ae33faa2dec15c
/path/referenced/by/symlink

(Note 120000 is the mode listed in ls-files output. It would be something like 100644 for a regular file.)

But what does Git do with this object when you check it out from the repository and into your filesystem? It depends on the core.symlinks config. From man git-config:

core.symlinks

If false, symbolic links are checked out as small plain files that contain the link text.

So, with a symbolic link in the repository, upon checkout you either get a text file with a reference to a full filesystem path, or a proper symbolic link, depending on the value of the core.symlinks config.

Either way, the content of the path referenced by the symlink is not stored in the repository (unless the referenced path is also in the repository, of course).

3

  • 1

    Is the link path that’s stored in the remote guaranteed to be relative if it points to a path inside the repo? What about paths to outside the repo? Is it absolute or relative to the root of project? Does it depend on how the link is made?

    – geekley

    Nov 14, 2020 at 2:10

  • Yeah I think it depends on how you create the symlink. If you create it and the destination is prefixed with a /, then it will be absolute and may point outside your repo. Otherwise, it will be relative. If it’s relative and points into your repo, it should be portable, at least between Unix-like systems.

    Nov 14, 2020 at 2:43


  • 1

    @geekley Not sure how I dropped this by accident during editing, but you can see the contents of a git store object with git cat-file -p, so if your symlink’s hash is c6e5580589892eb40407c74a825afaa6c9315787, you can do git cat-file -p c6e5580589892eb40407c74a825afaa6c9315787 and see that pack file’s contents, which is just a symlink

    Nov 14, 2020 at 2:48


152

“Editor’s” note: This post may contain outdated information. Please see comments and this question regarding changes in Git since 1.6.1.

Symlinked directories:

It’s important to note what happens when there is a directory which is a soft link.
Any Git pull with an update removes the link and makes it a normal directory. This is what I learnt hard way. Some insights here and here.

Example

Before

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir

git add/commit/push

It remains the same

After git pull AND some updates found

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir

7

  • 6

    It’s worth noting that these warnings about symlinked directories do not apply to versioned symlinks. The major edge case in question was that of folks symlinking some or all of the working tree into a different path (say onto a different partition with more disk space) and expecting git to check out code through the existing symlink. That is, if you have a project that contains versioned symlinks to files or directories, the normal symlink-as-blob behavior will preserve symlinks, correctly version changes to those symlinks, and otherwise work as expected.

    Dec 22, 2009 at 1:18


  • 22

    Is this behavior present on all versions of git or has this been fixed with?

    – jbotnik

    Jun 9, 2011 at 20:28


  • 24

    It seems like this behaviour is fixed now, see: stackoverflow.com/a/1943656/1334781

    Sep 25, 2014 at 8:15

  • 2

    Shekar: Will you place edit your answer to reflect changes in git in recent years?

    – einpoklum

    Jun 22, 2017 at 18:46

  • 1

    @RonWertlen That is a link to this same question.

    – alx

    Aug 5, 2020 at 8:33