42

Is it possible in git to have a "link" to a particular file in a git repo? Like what git submodules do for folders but my question is about a particular file, not a full directory:

my-project/
    class1.java
    class2.java
    logback.xml (link to a particular file, say https://github.com/theHilikus/JRoboCom/blob/master/jrobocom-core/src/main/resources/logback.xml)

So as can be seen, in this case it doesn't make sense to have a whole submodule folder, it is just one file.
I'm ok with the link being locked to a particular commit but it would be better if it's moving as it changes in its own project's lifecycle

As a note, this has nothing to do with file-system's symbolic links; I'm talking about a reference to a file in another project, repo, branch, or anything. it's ok if the content of the file is a duplicate and not a file-system symlink

Hilikus
  • 8,557
  • 12
  • 57
  • 100
  • I don't know of a way in git... but instead of having git manage the file, but maybe you could have your build system (maven?) download the file when needed? Ref: http://stackoverflow.com/questions/2741806/maven-downloading-files-from-url – Charlie Apr 05 '13 at 22:26
  • possible duplicate of [SVN:externals equivalent in GIT?](http://stackoverflow.com/questions/571232/svnexternals-equivalent-in-git) – Schwern Jan 04 '15 at 21:26
  • 1
    possible duplicate of [Linking a single file from another git repository](http://stackoverflow.com/questions/7597748/linking-a-single-file-from-another-git-repository) – Joe Jan 05 '15 at 08:49

3 Answers3

51

Git has features that you can use to achieve what you need. It supports file system symlinks and it supports submodules. Submodules is already a standard way to handle references to other repositories. You can use them in conjunction with a way to reference files locally. That can be handled directly using relative symbolic links or indirectly using a script that copies over files from the submodule to where you need them.

You should have one submodule per external git tree and you should treat the submodules with care, as they are not only links to external repositories but also to their specific commits. The following to solutions will show you how to use individual files from an external repostiory but still maintain all the advantages of submodules.

An alternative way is to fetch the files directly but then you will lose the advantage of submodules entirely or you will have to build the features yourself. As I already stated, submodules are the standard way to handle this sort of task and you should use it unless you have special needs like to avoid downloading other files at all cost.

Using a submodule and a symlink

Once you have a submodule ready, you can just add filesystem symlinks pointing into the submodule directory structure.

Run this in a shell in your project directory:

$ git submodule add https://github.com/theHilikus/JRoboCom
$ ln -s JRoboCom/jrobocom-core/src/main/resources/logback.xml
$ git add .gitmodules logback.xml
$ git commit -m "add a symbolic link to logback.xml with the respective submodule"

Now you have a symlink:

logback.xml -> JRoboCom/jrobocom-core/src/main/resources/logback.xml

Using a submodule and a script

As an alternative, you can use custom scripts that copy over ordinary files from your submodules. In very special cases you could handle the external repositories from the script without submodules but I would normally not recommend it.

Create a file bootstrap.sh containing:

#!/bin/sh
git submodule init
git submodule update

cp JRoboCom/jrobocom-core/src/main/resources/logback.xml .

Run this in a shell in your project directory:

$ git submodule add https://github.com/theHilikus/JRoboCom
$ git add .gitmodules bootstrap.sh
$ git commit -m "add a script to fetch logback.xml from the respective submodule"

Note that we are not adding the logback.xml file to Git, as it will be fetched from the submodule.

Instruct users of the repository to first run the script above. It will prepare their repositories for using submodules, will fetch the submodule data and will copy the file to its location. Sometimes there's already some sort of bootstrap script in the project.

Using a script to fetch a single file via git protocol

Found another solution for Git >= 1.7.9.5 using git archive.

Create a file bootstrap.sh containing:

#!/bin/sh
git archive --remote=https://github.com/theHilikus/JRoboCom master:JRoboCom/jrobocom-core/src/main/resources logback.xml | tar -x

Run this in a shell in your project directory:

$ git add bootstrap.sh
$ git commit -m "add a script to fetch logback.xml directly from the remote project"

Using a script to fetch a single file via HTTP

If the repository hosting service also serves the individual files via HTTP, you can simply use curl or wget to download them.

Create a file bootstrap.sh containing:

#!/bin/sh
curl -O https://raw.githubusercontent.com/theHilikus/JRoboCom/master/jrobocom-core/src/main/resources/logback.xml

Run this in a shell in your project directory:

$ git add bootstrap.sh
$ git commit -m "add a script to fetch logback.xml directly from github"

Notes on scripts fetching single files

You could also store the references in files with a specific extention (like *.url) or maintain the list of references in one file (like .references in your project directory) and build a more comprehensive script that goes through all the references and downloads the respective files.

Pavel Šimerda
  • 4,526
  • 1
  • 25
  • 30
  • 2
    I guess this won't work in Windows because of the use of symbolic links? Or is there a Windows workaround? – RayCh Sep 18 '18 at 16:28
  • Does the bootstrap.sh get executed whenever the repo is cloned ? – abhishek phukan Jul 25 '19 at 13:31
  • I was trying to fetch a single file using the git protocol, and the repo was on github. Git archive isn't supported against github servers at this time. An alternative was to use svn as mentioned at https://stackoverflow.com/a/18324428/999165. – balast Jul 28 '20 at 23:26
3

The accepted answer seems misleading since Git can handle symlinks just fine as long as the operating system used by all developers supports them.

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

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

SO References:

How does git handle symbolic links?

Git - how to handle symlinks

How can I get git to follow symlinks?

Community
  • 1
  • 1
Jeach
  • 7,653
  • 7
  • 43
  • 56
  • 3
    This answer speaks about internal symlinks, not symlinks to external resources, please see my answer. – Pavel Šimerda Jan 04 '15 at 21:20
  • 1
    Really? Pleas read the title again, and then, read the very first sentence. – Jeach Jan 04 '15 at 21:22
  • 1
    I don't see your point. Also if you downvote, it's nice to drop a comment explaining the downvote, if that one was yours. Downvoting is a QA tool, not a tool for revenge. – Pavel Šimerda Jan 04 '15 at 21:31
  • 1
    @PavelŠimerda I was searching for a similar subject when I fell on this question/answer which happens to be asked by a friend of mine (he'll recognize me). When I saw the answer, I simply pointed out to him (via a post) that based on the question, the accepted answer seemed very misleading. If someone unfamiliar with GIT and symlinks fall on this question I don't want them to instantly think that GIT does not support symlinks. You can down-vote all you want. – Jeach Jan 04 '15 at 23:59
  • 3
    @Jeach look at the final paragraph in the original question. You are misinterpreting the first sentence. – Andrew C Jan 05 '15 at 00:17
  • @AndrewC If SO relied on the final paragraph in order to determine what a question was about it would be in trouble. Titles is mostly what is used and some will read the first few paragraphs before moving on to the correct answer. – Jeach Jan 07 '15 at 05:15
  • As of this time, the title and content clearly indicate that the intent is to use only a single file from a remote repo, and explicitly says like git submodules but for a single file. Additionally, this is more appropriately a comment, since it doesn't answer the (assumed) question, which is still a "how do I" – John Neuhaus Apr 27 '18 at 15:48
-1

Unfortunately, no. The only type of external reference you can have in git is through submodules, which puts the entire branch in a directory. You'll need to create a script or something to help fetch the file from the desired location and put it in your working tree.

John Szakmeister
  • 38,342
  • 9
  • 78
  • 72
  • 1
    Submodules are the standard way to handle external references. You can use them together with filesystem symlinks or with scripts, please see my answer. – Pavel Šimerda Jan 04 '15 at 21:19
  • 1
    @PavelŠimerda Yes, but you can only have an entire tree as a submodule--which I already stated in my answer. The OP wants to point to a *single file*, which you cannot do with submodules. Sorry, but your answer adds nothing to the conversation. – John Szakmeister Jan 04 '15 at 21:51
  • My answer described two different solutions to point to a file using submodules. I edited it heavily and I hope the intention is much clearer now. – Pavel Šimerda Jan 05 '15 at 09:06