Search code examples
bashgitsparse-checkout

having trouble with a git sparse checkout (folder)


here is my git server tree:

----a/
    |--b/
    |--c/
    |--d/
       |--e/
          |--f/
             |--g.txt
          |--h.readme

here is my git version tree

---------------->master
    |---->myBranch [files are up to date here]

here is my jenkins server tree

-----A/
     |--B/
     |--C/

I am trying to checkout the content of repository "e" in repository "B" I just need the last version of the current branch i'm working on, and I don't want to commit, just to get some up-to-date read-only scripts to run, so depth 1 is okay I guess.

Anyway, The problem I'm facing is that I'm able to to a sparse checkout with

#############################
#####    1/ configuring local folder
#############################
git init
git config core.sparseCheckout true
#an empty repository with the remote is created:
git remote add -f origin ssh://[email protected]:port/myProjects/thisProject.git
#add repository "e" to be checked out:
echo e/*> .git/info/sparse-checkout
#############################
#####    2/ fetching/updating files
#############################
git fetch 
git checkout myBranch

I know I'm close, but what I get is this:

-----A/
     |--B/
     |  |----a/
     |       |--d/
     |          |--e/
     |             |--f/
     |                |--g.txt
     |             |--h.readme
     |--C/

not this (which is what I want)

-----A/
     |--B/
     |  |--f/
     |     |--g.txt
     |  |--h.readme
     |--C/

any hints?

by the way I tried different ways of using "depth 1" for "step 2" with no success:

git fetch --depth 1 $(url) $(branch)
git checkout $(branch)

--> error: pathspec 'myBranch' did not match any file(s) known to git.

git fetch --depth 1 $(url) $(branch)
git checkout 

--> fatal: You are on a branch yet to be born

git fetch --depth 1 $(url) $(branch)
git checkout -b $(branch) 

fatal: A branch named 'myBranch' already exists.

git fetch
git checkout $(branch)

--> works as describe above


Solution

  • Git doesn't store directories, only files. So, given your drawing here:

    ----a/
        |--b/
        |--c/
        |--d/
           |--e/
              |--f/
                 |--g.txt
              |--h.readme
    

    the repository has some commits that have files named:

    a/d/e/f/g.txt
    

    and:

    a/d/e/h.readme
    

    You can direct your Git to check out these specific files, using either command line options or the sparse checkout option you're attempting to use. Their names will still be a/d/e/f/g.txt and a/d/e/h.readme.

    Your computer probably requires that these names be created by making a directory (or folders) named a, then making one named d in a, and so on. Git will do that. You cannot make Git use any other name for these files if you're going to use git checkout to extract them.1

    So, that leaves you with the option of not using git checkout to get these files. You could get the commit (as you are doing already), then use git show on individual path names, for instance. The standard output of git show will show the file's contents; you can redirect this to a file name of your choice.

    Since you don't want the whole repository, consider using git archive to turn one commit into an archive. Since you don't want the whole commit either, consider adding to this git archive command the name(s) of the file(s) that you want archived.2 You may then have an un-archiver that can skip the a/d/ part of the path names of each archived file. For instance, GNU tar has --strip-components.


    1I think it would be nice to be able to remap stored file names to in-file-system names, for many reasons, including the case-folding issues and cheeky Linux programmers creating files named CON and LPT. :-) But Git can't, at least not today.

    2This isn't required, and if you're downloading this kind of git archive from a hosting server such as GitHub, you may not be able to do that. But if you can do that, you'll save some amount of space and transfer time. Given your ssh://user@host URL, you can probably run ssh user@host "cd path/to/repo; git archive ..." and pipe the result to a local tar -xf -, for instance.