ChatGPT解决这个技术问题 Extra ChatGPT

How to get a copy of an older version of a file in a git repository?

I have a version of a .tex file from a number of commits ago that I would like to get a copy of. I have the sha1 hash value for the commit that has the version of that file that I want. I do not want to replace the current version of the file. Rather, I want to just get a separate copy of it that reflects its state at the older version.

A lot of similar questions suggest using git checkout <sha1> -- file.tex, but this just keeps giving "error: pathspec 'file.tex' did not match any file(s) known to git."

The file I am interested in originally existed in the top-level directory of the repository. I am currently in a sub-directory of the repository trying to run this command so as to get the older version of file.tex in the subdirectory.

Is this possible? How can I do this?

Make a copy of the current file, and then run git checkout <commit-id> file.ext?

q
qqx

You can use git cat-file to dump the contents of the file to the standard output and redirect that into your desired destination:

git cat-file -p <sha1>:./file.tex > wherever.tex

The ./ is necessary if you are in a subdirectory of the repository, if you're in the top-level of the repository it may be omitted. Also, that may not work in older versions of git, in which case you'd need to explicitly supply the full path to the file relative to the repository's root.


Note that, unlike many other git commands, the filename (here "file.tex") must be the name from the root of the git repo; so if you want foo/file.tex and you are down in subdirectory foo you can't type the above, you would have to type :foo/file.tex despite the fact that you are already in foo.
@Daniel, that is true. But, at least with recent versions of git you can always use . to refer to the current directory. I've updated my answer to reflect this.
And now I believe in reincarnation.
Great. Would git cat-file -p ^:./file.tex > wherever.tex get the version of the file from the previous commit?
@ATL_DEV, any command syntax to do this needs to specify (1) the command to use, (2) the path/file to get, (3) the label or sha of the commit and (4) the destination of the file copy. How would you make the syntax any simpler?
g
gws

Use git show with absolute repository paths:

workdir$ git show revision:repo/module/package/code.file > code.file.old

or paths relative to the current directory:

package$ git show revision:./code.file > workdir/code.file.old

In contrast to checking out a file, show does not intrinsically change your workspace, you can do anything you like with the output.

Credit to this answer, and of course see full details in the manual.


This is clearly the most accurate answer as it do not change the version/status of the repository and allow to recover any state of the repo.
J
Jon-Eric

I think that the best solution is to overwrite temporally your file. In your top-level of your repository:

git checkout <sha1> file.tex
cp file.tex directory
git checkout HEAD file.tex

this is the best solution I have seen so far. I am still annoyed that there doesn't seem to be a way to just directly grab that file.
That last command would need to be git checkout HEAD file.tex. The first checkout command would modify the index as well as the working tree copy, so checkout without specifying a revision would still use the older version.