How can I get Git to follow symlinks?

Viewed 113886

Is my best be going to be a shell script which replaces symlinks with copies, or is there another way of telling Git to follow symlinks?

PS: I know it's not very secure, but I only want to do it in a few specific cases.

14 Answers

What I did to add to get the files within a symlink into Git (I didn't use a symlink but):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Do this command in the Git-managed directory. TARGETDIRECTORY has to be created before the SOURCEDIRECTORY is mounted into it.

It works fine on Linux, but not on OS X! That trick helped me with Subversion too. I use it to include files from an Dropbox account, where a webdesigner does his/her stuff.

If you want to make this bind permanent add the following line to /etc/fstab:

/sourcedir /targetdir none bind

NOTE: This advice is now out-dated as per comment since Git 1.6.1. Git used to behave this way, and no longer does.


Git by default attempts to store symlinks instead of following them (for compactness, and it's generally what people want).

However, I accidentally managed to get it to add files beyond the symlink when the symlink is a directory.

I.e.:

  /foo/
  /foo/baz
  /bar/foo --> /foo
  /bar/foo/baz

by doing

 git add /bar/foo/baz

it appeared to work when I tried it. That behavior was however unwanted by me at the time, so I can't give you information beyond that.

On macOS (I have Mojave/ 10.14, git version 2.7.1), use bindfs.

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

It's been hinted by other comments, but not clearly provided in other answers. Hopefully this saves someone some time.

I used to add files beyond symlinks for quite some time now. This used to work just fine, without making any special arrangements. Since I updated to Git 1.6.1, this does not work any more.

You may be able to switch to Git 1.6.0 to make this work. I hope that a future version of Git will have a flag to git-add allowing it to follow symlinks again.

Hmmm, mount --bind doesn't seem to work on Darwin.

Does anyone have a trick that does?

[edited]

OK, I found the answer on Mac OS X is to make a hardlink. Except that that API is not exposed via ln, so you have to use your own tiny program to do this. Here is a link to that program:

Creating directory hard links in Mac OS X

Enjoy!

An alternative implementation of what @user252400 proposes is to use bwrap, a small setuid sandbox that can be found in all major distributions - often installed by default. bwrap allows you to bind mount directories without sudo and automatically unbinds them when git or your shell exits.

Assuming your development process isn't too crazy (see bellow), start bash in a private namespace and bind the external directory under the git directory:

bwrap --ro-bind / / \
      --bind {EXTERNAL-DIR} {MOUNTPOINT-IN-GIT-DIR} \
      --dev /dev \
      bash

Then do everything you'd do normally like git add, git commit, and so on. When you're done, just exit bash. Clean and simple.

Caveats: To prevent sandbox escapes, bwrap is not allowed to execute other setuid binaries. See man bwrap for more details.

1. You should use hard links as changes made in the hard links are staged by git.

2. The syntax for creating a hard link is ln file1 file2.

3. Here file1 is the location of the file whose hard link you want to create and file2 is the location of the hard link .

4. I hope that helps.

I'm using Git 1.5.4.3 and it's following the passed symlink if it has a trailing slash. E.g.

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Related