Home > Blockchain >  Git: How to get specified version of all files in a folder but not descendant folders given a commit
Git: How to get specified version of all files in a folder but not descendant folders given a commit

Time:08-24

I'm trying to get the versions of all files in a folder (but not in subfolders) including deletions.

Given a git repo with the following history:

$ git log --oneline
e654806 (HEAD -> master) Adding content to bar files
e43071a 3rd commit
1686e2f 2nd commit
3f21424 Initial commit

Trying to check out a version with a deleted file (added in e43071a) fails with:

git checkout 1686e2f foo/*.txt
error: pathspec 'foo/5.txt' did not match any file(s) known to git

So I delete all files in foo/ and checkout again

rm foo/*.txt
git checkout 1686e2f foo/*.txt

I was surprised to find that this gave me the version of all files both in foo and foo/bar from 1686e2f

$ git st
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   foo/1.txt
    modified:   foo/2.txt
    modified:   foo/bar/3.txt
    modified:   foo/bar/4.txt

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    deleted:    foo/5.txt

how would I go about only getting the file versions of 1686e2f in foo but not in foo/bar?

CodePudding user response:

Read the pathspec section of the gitglossary(7) man page, which tells us:

the rest of the pathspec is a pattern for the remainder of the pathname. Paths relative to the directory prefix will be matched against that pattern using fnmatch(3); in particular, * and ?can match directory separators.

So that's why you're getting both foo/*.txt and foo/bar/*.txt. If you keep reading, you'll find that you can add flags to the pathspec that modify that behavior:

glob

Git treats the pattern as a shell glob suitable for consumption by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not match a / in the pathname. For example, Documentation/*.html matches Documentation/git.html but not Documentation/ppc/ppc.html or tools/perf/Documentation/perf.html.

That means we can write this:

git checkout 1686e2f ':(glob)foo/*.txt'

And that will match only files in foo/ with a .txt extension.

  •  Tags:  
  • git
  • Related