21

Is there a way to perform a git checkout for only certain file types (.xlf), which recurses down through the entire repository? The results should contain the struture of the repository, meaning the folders, and the contained files of a certain extension.

Repo A

file.xlf
file.txt
level2/
    file2.xlf
    file2.txt
    level3/
        file3.xlf
        file3.txt 

After checkout repo B looks like:

Repo B

file.xlf
    /level2
    file2.xlf
        /level3
        file3.xlf

This is what I have so far:

$ git checkout FETCH_HEAD -- '*.xlf'

This gives all of the ".xlf" files at the root level, but is not recursive down to subdirectories.

Thank you for the help.

eduludi
  • 1,618
  • 21
  • 23
user5088790
  • 213
  • 1
  • 2
  • 6

6 Answers6

32

You don't need find or sed, you can use wildcards as git understands them (doesn't depend on your shell):

git checkout -- "*.xml"

The quotes will prevent your shell to expand the command to only files in the current directory before its execution.

You can also disable shell glob expansion (with bash) :

set -f
git checkout -- *.xml

This, of course, will irremediably erase your changes!

Dadaso Zanzane
  • 6,039
  • 1
  • 25
  • 25
  • This is most definitely the cleanest solution. – mariocatch Jul 20 '18 at 15:35
  • How to match everything _except_ a specific type of file? – mmKALLL Oct 12 '18 at 13:37
  • 1
    This works recursively? It doesn't on Windows, at least. – aoetalks Oct 26 '18 at 16:45
  • 4
    @aoetalks For me it works recursively. But only the `git checkout -- "*.xml"` version (checking out from index) the `git checkout HEAD -- "*.xml"` (checkoing out from branch name) looks like doesn't work recursively. – Mariusz Pawelski Dec 27 '18 at 23:33
  • `git checkout HEAD -- **/*.xml` is how you could have it recursively go thru the current directories folders and then checkout all the .xmls in those folders. if there's more folders within those folders, unfortunately have to chain it like this `**/**/*.xml` and so on. – Benji Weiss Jan 25 '23 at 16:28
17

UPDATE: Check Dadaso's answer for a solution that will work in most of cases.

You can try something like this, using git ls-tree and grep:

git checkout origin/master -- `git ls-tree origin/master -r --name-only | grep ".xlf"`

Note this expects a remote origin in a master branch. Also you must provide the right filter/extension to grep.

Before this command, you should have done something like this:

git init
git remote add origin <project.git>
git fetch
eduludi
  • 1,618
  • 21
  • 23
  • 1
    Thank you, this solved the problem. One thing to note, as it happened to me, is if there is a typo in the file extension, git squawks about a "Detached Head". If the file extension is found, then this message does not occur. – user5088790 Jul 09 '15 at 07:33
4

Dadaso's answer git checkout -- "*.xml" checks out all .xml files recursively from index to working directory.

However for some reasons git checkout branch-name -- "*.xml" (checking out files from branch-name branch) doesn't work recursively and only checks "xml" files in root directory.

So IMO the best is to use git ls-tree then filter file names you are interested in and pass it to git checkout branch-name --. Here are the commands you can use:

  • Bash (and git bash on windows) version:

    git ls-tree branch-name --full-tree --name-only -r | grep "\.xml" | xargs git checkout branch-name --
    
  • cmd (windows) version (if you don't have "C:\Program Files\Git\usr\bin" in you PATH):

    git ls-tree branch-name --full-tree --name-only -r | "C:\Program Files\Git\usr\bin\grep.exe" "\.xml" | "C:\Program Files\Git\usr\bin\xargs.exe" git checkout branch-name --
    
  • for powershell it's still better to call cmd.exe because it's much faster (powershell doesn't have good support for native stdin/stdout pipelining):

    cmd.exe /C 'git ls-tree branch-name --full-tree --name-only -r | "C:\Program Files\Git\usr\bin\grep.exe" "\.xml" | "C:\Program Files\Git\usr\bin\xargs.exe" git checkout branch-name --'
    
  • However you you have small number of files you can try this in powershell (like in @aoetalks answer). But I found it extremely slow for couple of houndeds files:

    git ls-tree branch-name --full-tree --name-only -r | sls "\.xml" | %{ git checkout branch-name -- $_ }
    
Mariusz Pawelski
  • 25,983
  • 11
  • 67
  • 80
2

On PowerShell (Windows, haven't tried PowerShell Core+Linux), I was able to do it like this

git ls-tree master -r --name-only | sls ".cscfg" | foreach { git checkout origin/master -- $_ }

aoetalks
  • 1,741
  • 1
  • 13
  • 26
  • This one finally worked for me because my directories have spaces in them. I just had to put "" around the $_ part. – KeizerHarm Dec 15 '20 at 14:19
0

No; git operates at a whole-repository (and whole-history) level; there's no way of getting a partial checkout of a repository. You can of course check out the repository and then delete everything that doesn't match your file, but of course you gain virtually nothing by doing so.

AlBlue
  • 23,254
  • 14
  • 71
  • 91
0

I had troubles with the solutions provided, and here is my solution

  1. checkout all change from the other branch git checkout branch -- ./
  2. only stage the certain type git add \*.type
  3. commit staged files git commit
  4. reset the other files git reset --hard
desertnaut
  • 57,590
  • 26
  • 140
  • 166
Seeliang
  • 2,321
  • 1
  • 13
  • 18