threads / discuss / 56143

Extracting a file

Subject: Extracting a file

## tl;dr

8 messages between Jul 22, 2021 and Jul 23, 2021.

replies: 7people: 5as markdown or json

Angelo Borsotti· Jul 22, 2021, 08:48 UTC · lore
Hi,

sometimes there is a need to extract a file from a commit. E.g. some changes have been applied to it in the work directory, and the app being implemented no longer works properly. It would be fine to have a look at that file, some commits ago, when all worked fine. Of course, it is possible to recover the entire old commit, or to make a new branch, or checkout the file (which requires to save the new one before), but the most simple and safe way is to extract the file, giving it a new name. That is possible, using this (hard to remember) trick:

git show HASH:file/path/name.ext > some_new_name.ext

Would not be better to have a "copy" command to copy a file from a commit to a new one in the current directory? This would make a git repository resemble a (readonly) filesystem, which actually it is. Note also that the ability to get from a repository what one has stored in it is the most basic feature anyone wants from a repository.

Thank you -Angelo Borsotti

Ævar Arnfjörð Bjarmason· Jul 22, 2021, 09:05 UTC · re: Angelo Borsotti · lore

Re: Extracting a file

On Thu, Jul 22 2021, Angelo Borsotti wrote:
Show 17 quoted lines
> Hi,
>
> sometimes there is a need to extract a file from a commit.
> E.g. some changes have been applied to it in the work directory,
> and the app being implemented no longer works properly.
> It would be fine to have a look at that file, some commits ago,
> when all worked fine.
> Of course, it is possible to recover the entire old commit, or to
> make a new branch, or checkout the file (which requires to save
> the new one before), but the most simple and safe way is to
> extract the file, giving it a new name.
> That is possible, using this (hard to remember) trick:
>
> git show HASH:file/path/name.ext > some_new_name.ext
>
> Would not be better to have a "copy" command to copy a file from a commit
> to a new one in the current directory?
That's an interesting feature request, FWIW you can do this now with:
    git mv A B &&
    git checkout HEAD -- A

I wonder if having a "git copy" for that would be more confusing that not, i.e. a frequent difficulty new users used to have with git if they were used to cvs/svn was to look for a "copy" command, thinking that git's data model (like those older VCS's) needed the user to use a "mv" or "copy" to track history.

On the other hand perhaps git's so thoroughly established that it's not much of an educational issue anymore.

> This would make a git repository resemble a (readonly) filesystem, which
> actually it is.
> Note also that the ability to get from a repository what one has stored
> in it is the most basic feature anyone wants from a repository.

Git is actively not such a "read-only FS" in the sense of some version control systems, i.e. needing to declare that you are now going to "edit" the file etc.

It is for bare repositories, but a checkout explicitly concerns itself with you doing arbitrary changes on the FS, and git needing to keep up.

So maybe there should be a "copy", but if your starting point for wanting it is to make git behave like a read-only FS I don't think that'll lead anywhere productive.

Angelo Borsotti· Jul 22, 2021, 09:46 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: Extracting a file

Hi,
thank you for your quick reply.

Actually, I did not want to make git behave like a read-only filesystem, but only to be able to get what is stored in it using some easy to remember command.

I guess that:
    git mv A B &&
    git checkout HEAD -- A

renames file A in the work, current, directory to B, and then recovers A from the repository. This changes the file on which I am working. After having read the old A, and understood what changes I make that are not correct, I should delete A, and rename B back to A. If something gets wrong with this, I risk to damage my original A. This is why it is better not to change it, and instead get a copy of the old one with another name, which is what

git show HASH:file/path/name.ext > some_new_name.ext
does.
-Angelo
On Thu, 22 Jul 2021 at 11:13, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
Show 51 quoted lines
>
>
> On Thu, Jul 22 2021, Angelo Borsotti wrote:
>
> > Hi,
> >
> > sometimes there is a need to extract a file from a commit.
> > E.g. some changes have been applied to it in the work directory,
> > and the app being implemented no longer works properly.
> > It would be fine to have a look at that file, some commits ago,
> > when all worked fine.
> > Of course, it is possible to recover the entire old commit, or to
> > make a new branch, or checkout the file (which requires to save
> > the new one before), but the most simple and safe way is to
> > extract the file, giving it a new name.
> > That is possible, using this (hard to remember) trick:
> >
> > git show HASH:file/path/name.ext > some_new_name.ext
> >
> > Would not be better to have a "copy" command to copy a file from a commit
> > to a new one in the current directory?
>
> That's an interesting feature request, FWIW you can do this now with:
>
>     git mv A B &&
>     git checkout HEAD -- A
>
> I wonder if having a "git copy" for that would be more confusing that
> not, i.e. a frequent difficulty new users used to have with git if they
> were used to cvs/svn was to look for a "copy" command, thinking that
> git's data model (like those older VCS's) needed the user to use a "mv"
> or "copy" to track history.
>
> On the other hand perhaps git's so thoroughly established that it's not
> much of an educational issue anymore.
>
> > This would make a git repository resemble a (readonly) filesystem, which
> > actually it is.
> > Note also that the ability to get from a repository what one has stored
> > in it is the most basic feature anyone wants from a repository.
>
> Git is actively not such a "read-only FS" in the sense of some version
> control systems, i.e. needing to declare that you are now going to
> "edit" the file etc.
>
> It is for bare repositories, but a checkout explicitly concerns itself
> with you doing arbitrary changes on the FS, and git needing to keep up.
>
> So maybe there should be a "copy", but if your starting point for
> wanting it is to make git behave like a read-only FS I don't think
> that'll lead anywhere productive.
Jeff King· Jul 23, 2021, 07:01 UTC · re: Angelo Borsotti · lore

Re: Extracting a file

On Thu, Jul 22, 2021 at 11:46:01AM +0200, Angelo Borsotti wrote:
Show 22 quoted lines
> Actually, I did not want to make git behave like a read-only filesystem,
> but only to be able to get what is stored in it using some easy to remember
> command.
> 
> I guess that:
> 
>     git mv A B &&
>     git checkout HEAD -- A
> 
> renames file A in the work, current, directory to B, and then recovers
> A from the
> repository. This changes the file on which I am working. After having
> read the old
> A, and understood what changes I make that are not correct, I should delete A,
> and rename B back to A.
> If something gets wrong with this, I risk to damage my original A.
> This is why it is
> better not to change it, and instead get a copy of the old one with
> another name,
> which is what
> 
> git show HASH:file/path/name.ext > some_new_name.ext

You might also like "git checkout -p HASH -- A", which will let you pick individual hunks from HASH:A and apply them to your working tree.

-Peff
Angelo Borsotti· Jul 23, 2021, 07:38 UTC · re: Jeff King · lore

Re: Extracting a file

Hi,
> You might also like "git checkout -p HASH -- A", which will let you pick
> individual hunks from HASH:A and apply them to your working tree.

This shows the differences between the committed and the current file, in a patch form, which is handy to apply to the current file to make it equal to the old, but not if I want to browse the old file and understand how it was before. Moreover, the command ends by asking:

    Apply deletion to index and worktree [y,n,q,a,d,?]?

and when I must be very careful to provide the correct answer so as not to damage my files. So many alternatives to simply get a file from the repo, some of which potentially dangerous, show that there is a need for a simple, safe command to get it.

-Angelo
On Fri, 23 Jul 2021 at 09:01, Jeff King <peff@peff.net> wrote:
Show 30 quoted lines
>
> On Thu, Jul 22, 2021 at 11:46:01AM +0200, Angelo Borsotti wrote:
>
> > Actually, I did not want to make git behave like a read-only filesystem,
> > but only to be able to get what is stored in it using some easy to remember
> > command.
> >
> > I guess that:
> >
> >     git mv A B &&
> >     git checkout HEAD -- A
> >
> > renames file A in the work, current, directory to B, and then recovers
> > A from the
> > repository. This changes the file on which I am working. After having
> > read the old
> > A, and understood what changes I make that are not correct, I should delete A,
> > and rename B back to A.
> > If something gets wrong with this, I risk to damage my original A.
> > This is why it is
> > better not to change it, and instead get a copy of the old one with
> > another name,
> > which is what
> >
> > git show HASH:file/path/name.ext > some_new_name.ext
>
> You might also like "git checkout -p HASH -- A", which will let you pick
> individual hunks from HASH:A and apply them to your working tree.
>
> -Peff
Junio C Hamano· Jul 23, 2021, 16:47 UTC · re: Angelo Borsotti · lore

Re: Extracting a file

Angelo Borsotti <angelo.borsotti@gmail.com> writes:
Show 8 quoted lines
>> You might also like "git checkout -p HASH -- A", which will let you pick
>> individual hunks from HASH:A and apply them to your working tree.
>
> This shows the differences between the committed and the current file,
> in a patch
> form, which is handy to apply to the current file to make it equal to
> the old, but
> not if I want to browse the old file and understand how it was before.

Why doesn't a straight-forward "check out the path from an old version" work? That is

    git checkout $old_version -- path/to/file.ext

Is it because you have changes to path/to/file.ext already (in which case "mv path/to/file.ext path/to/file.ext-saved" would be a quick way to save it away)?

And then path/to/file.ext can be inspected to your heart's content, and when you are done and want to go back to the current state, you can do "git checkout HEAD -- path/to/file.ext" (followed by the earlier "mv" in reverse)?

Junio C Hamano· Jul 23, 2021, 16:50 UTC · re: Jeff King · lore

Re: Extracting a file

Jeff King <peff@peff.net> writes:
Show 27 quoted lines
> On Thu, Jul 22, 2021 at 11:46:01AM +0200, Angelo Borsotti wrote:
>
>> Actually, I did not want to make git behave like a read-only filesystem,
>> but only to be able to get what is stored in it using some easy to remember
>> command.
>> 
>> I guess that:
>> 
>>     git mv A B &&
>>     git checkout HEAD -- A
>> 
>> renames file A in the work, current, directory to B, and then recovers
>> A from the
>> repository. This changes the file on which I am working. After having
>> read the old
>> A, and understood what changes I make that are not correct, I should delete A,
>> and rename B back to A.
>> If something gets wrong with this, I risk to damage my original A.
>> This is why it is
>> better not to change it, and instead get a copy of the old one with
>> another name,
>> which is what
>> 
>> git show HASH:file/path/name.ext > some_new_name.ext
>
> You might also like "git checkout -p HASH -- A", which will let you pick
> individual hunks from HASH:A and apply them to your working tree.
There is
    git cat-file --textconv --filters HASH:A >my-temporary-file-to-inspect

which would not touch the index or any tracked working tree file, other than the target of redirection.

Felipe Contreras· Jul 23, 2021, 18:17 UTC · re: Junio C Hamano · lore

Re: Extracting a file

Junio C Hamano wrote:
Show 36 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> > On Thu, Jul 22, 2021 at 11:46:01AM +0200, Angelo Borsotti wrote:
> >
> >> Actually, I did not want to make git behave like a read-only filesystem,
> >> but only to be able to get what is stored in it using some easy to remember
> >> command.
> >> 
> >> I guess that:
> >> 
> >>     git mv A B &&
> >>     git checkout HEAD -- A
> >> 
> >> renames file A in the work, current, directory to B, and then recovers
> >> A from the
> >> repository. This changes the file on which I am working. After having
> >> read the old
> >> A, and understood what changes I make that are not correct, I should delete A,
> >> and rename B back to A.
> >> If something gets wrong with this, I risk to damage my original A.
> >> This is why it is
> >> better not to change it, and instead get a copy of the old one with
> >> another name,
> >> which is what
> >> 
> >> git show HASH:file/path/name.ext > some_new_name.ext
> >
> > You might also like "git checkout -p HASH -- A", which will let you pick
> > individual hunks from HASH:A and apply them to your working tree.
> 
> There is
> 
>     git cat-file --textconv --filters HASH:A >my-temporary-file-to-inspect
> 
> which would not touch the index or any tracked working tree file,
> other than the target of redirection.

Hmm, --textconv and --filters are incompatible with each other, did you mean "--textconv | --filters"?

Also, this is simpler:
  git cat-file -p HASH:A
Although I don't know how that's better than Angelo's `git show`.

FTR I do often use `git show commit:file` myself. I'm not sure if we could do something particularly better than that.

-- 
Felipe Contreras

← back to recent threads