threads / discuss / 25423

Can I checkout a single file without altering index?

Subject: Can I checkout a single file without altering index?

## tl;dr

16 messages between Oct 12, 2010 and Oct 15, 2010.

replies: 15people: 11as markdown or json

Christian Halstrick· Oct 12, 2010, 10:03 UTC · lore

Can I checkout a certain file to a specific revision without also adding this content to the index? I only want to alter the working-tree - no modification of index or HEAD needed.

Here is why I need that: I see a bug in git controlled sources. I fix one source file and also add one unit test in a separate file. I checked that the test succeeds with my fix. The index now contains what I want to commit. Now I want to see whether my test fails without my fix. I want to checkout HEAD for the source file without destroying my index. In the end, after I saw that my test fails without my fix, I just want to say "git commit" without having to.

Michael J Gruber· Oct 12, 2010, 10:19 UTC · re: Christian Halstrick · lore

Re: Can I checkout a single file without altering index?

Christian Halstrick venit, vidit, dixit 12.10.2010 12:03:
Show 11 quoted lines
> Can I checkout a certain file to a specific revision without also adding this 
> content to the index? I only want to alter the working-tree - no modification of 
> index or HEAD needed.
> 
> Here is why I need that: I see a bug in git controlled sources. I fix one source
> file and also add one unit test in a separate file. I checked that the test
> succeeds with my fix. The index now contains what I want to commit.
> Now I want to see whether my test fails without my fix. I want to checkout HEAD
> for the source file without destroying my index. In the end, after I saw that my
> test fails without my fix, I just want to say "git commit" without having to.
> 
I would recommend to work on top of a trial commit, i.e.

git commit -m TheFix git checkout HEAD^ -- fixedfile.c git reset --hard

and git commit --amend if needed. (Alternatively, use stash.)
You can also use

git show HEAD:fixedfile.c > fixedfile.c git checkout fixed.file.c git commit -m TheFix

but I find this more cumbersome.
Michael
Stefan Naewe· Oct 12, 2010, 11:14 UTC · re: Christian Halstrick · lore

Re: Can I checkout a single file without altering index?

On 10/12/2010 12:03 PM, Christian Halstrick wrote:
Show 10 quoted lines
> Can I checkout a certain file to a specific revision without also adding this 
> content to the index? I only want to alter the working-tree - no modification of 
> index or HEAD needed.
> 
> Here is why I need that: I see a bug in git controlled sources. I fix one source
> file and also add one unit test in a separate file. I checked that the test
> succeeds with my fix. The index now contains what I want to commit.
> Now I want to see whether my test fails without my fix. I want to checkout HEAD
> for the source file without destroying my index. In the end, after I saw that my
> test fails without my fix, I just want to say "git commit" without having to.
commit the unit test first, and the fix as a second commit ?
Regards,
  Stefan
-- 
----------------------------------------------------------------
/dev/random says: Help endangered species - adopt a KGB operative.
Jared Hance· Oct 13, 2010, 17:09 UTC · re: Stefan Naewe · lore

Re: Can I checkout a single file without altering index?

Stefan Naewe <stefan.naewe <at> atlas-elektronik.com> writes:
> 
> On 10/12/2010 12:03 PM, Christian Halstrick wrote:
> > Can I checkout a certain file to a specific revision without also adding 
this 
> > content to the index? I only want to alter the working-tree - no 
modification of 
> > index or HEAD needed.
> > 
> > Here is why I need that: I see a bug in git controlled sources. I fix one 
source
> > file and also add one unit test in a separate file. I checked that the test
> > succeeds with my fix. The index now contains what I want to commit.
> > Now I want to see whether my test fails without my fix. I want to checkout 
HEAD
> > for the source file without destroying my index. In the end, after I saw 
that my
> > test fails without my fix, I just want to say "git commit" without having 
to.
Show 5 quoted lines
> 
> commit the unit test first, and the fix as a second commit ?
> 
> Regards,
>   Stefan
Just to add to this, since you might not want the test and the fix in separate 
commmits: (as is implied in the message)
  1. commit unit test.
  2. commit fix.
  3. go to detchatched head at HEAD^
  4. run unit test to insure that it fails.
  5. checkout the branch again to where you have the fix.
  6. run unit test to insure that it doesn't fail.
  7. run `git rebase HEAD^` and merge squash the two commits. (optional)
Alternatively, as others have pointed out, the stash should work as well.
Alex Riesen· Oct 12, 2010, 15:39 UTC · re: Christian Halstrick · lore

Re: Can I checkout a single file without altering index?

On Tue, Oct 12, 2010 at 12:03, Christian Halstrick <christian.halstrick@gmail.com> wrote:

> Can I checkout a certain file to a specific revision without also adding this
> content to the index? I only want to alter the working-tree - no modification of
> index or HEAD needed.
"git show <revision-specification>:path/name > path/name" ?
Tomas Carnecky· Oct 12, 2010, 16:39 UTC · re: Alex Riesen · lore

Re: Can I checkout a single file without altering index?

On 10/12/10 5:39 PM, Alex Riesen wrote:
Show 7 quoted lines
> On Tue, Oct 12, 2010 at 12:03, Christian Halstrick
> <christian.halstrick@gmail.com> wrote:
>> Can I checkout a certain file to a specific revision without also adding this
>> content to the index? I only want to alter the working-tree - no modification of
>> index or HEAD needed.
> 
> "git show <revision-specification>:path/name > path/name" ?

I heard that git-show doesn't apply filters to the file (smudge/clean or any custom ones). Keep that in mind when using it.

tom
Christian Halstrick· Oct 14, 2010, 08:03 UTC · re: Alex Riesen · lore

Re: Can I checkout a single file without altering index?

Thank's a lot for all your responses. I know now how to solve my problem. I'll definitely not going to commit my unit-test before my fix and publish that because then I would have commits in the history where tests fail. But other suggested solutions do work.

Still, all that sounds like workarounds for a lacking feature. Checkout content to the worktree without altering the index. What do you think, couldn't that be added as an option to checkout?

-- Chris
Neal Kreitzinger· Oct 15, 2010, 18:30 UTC · re: Christian Halstrick · lore

Re: Can I checkout a single file without altering index?

"Christian Halstrick" <christian.halstrick@gmail.com> wrote in message news:loom.20101014T095743-275@post.gmane.org...

Show 14 quoted lines
> Thank's a lot for all your responses. I know now how to solve my problem. 
> I'll
> definitely not going to commit my unit-test before my fix and publish that
> because then I would have commits in the history where tests fail. But 
> other
> suggested solutions do work.
>
> Still, all that sounds like workarounds for a lacking feature. Checkout 
> content
> to the worktree without altering the index. What do you think, couldn't 
> that be
> added as an option to checkout?
>
> -- Chris

FWIW, my understanding of the index is that it is the middle-man for moving things from your work-tree to the object-store AND for moving things from the object-store to your work-tree. Therefore, when you checkout the blob, it first gets copied from the object-store to your index and then from the index to your work-tree.

However, there is an option in git-commit to copy files directly from the working-tree to the object-store by totally bypassing the index, but no one seems to do this or recommend doing this as normative practice. None the less, this "exception" in the git-commit manpage does seem to set the precedent, so maybe it is also conceivable to copy objects directly from the object-store to the work-tree by totally bypassing the index.

Please note that I am responding because I am interested in the discussion and not because I know the answer. I am not a git programmer so my observations only symptomatic and/or theoretical as a user.

v/r, Neal

Jonathan Nieder· Oct 15, 2010, 18:43 UTC · re: Neal Kreitzinger · lore

Re: Can I checkout a single file without altering index?

Hi Neal,
Neal Kreitzinger wrote:
> However, there is an option in git-commit to copy files directly from the 
> working-tree to the object-store by totally bypassing the index

What option is this? I thought "git commit --include" added content to the index.

Jeff King· Oct 15, 2010, 18:55 UTC · re: Jonathan Nieder · lore

Re: Can I checkout a single file without altering index?

On Fri, Oct 15, 2010 at 01:43:02PM -0500, Jonathan Nieder wrote:
Show 7 quoted lines
> Neal Kreitzinger wrote:
> 
> > However, there is an option in git-commit to copy files directly from the 
> > working-tree to the object-store by totally bypassing the index
> 
> What option is this?  I thought "git commit --include" added content
> to the index.

git commit -o|--only, which is the same as "git commit <paths>". Of course it still uses an index, to create the tree, but it uses a temporary one based on HEAD instead of the current index contents.

-Peff
Jonathan Nieder· Oct 15, 2010, 19:32 UTC · re: Jeff King · lore

Re: Can I checkout a single file without altering index?

Jeff King wrote:
> On Fri, Oct 15, 2010 at 01:43:02PM -0500, Jonathan Nieder wrote:
>> Neal Kreitzinger wrote:
Show 9 quoted lines
>>> However, there is an option in git-commit to copy files directly from the 
>>> working-tree to the object-store by totally bypassing the index
>>
>> What option is this?  I thought "git commit --include" added content
>> to the index.
>
> git commit -o|--only, which is the same as "git commit <paths>". Of
> course it still uses an index, to create the tree, but it uses a
> temporary one based on HEAD instead of the current index contents.
Ah, it's stranger than that.
	 * A partial commit.
	 *
	 * (0) find the set of affected paths;
	 * (1) get lock on the real index file;
	 * (2) update the_index with the given paths;
	 * (3) write the_index out to the real index (still locked);
	 * (4) get lock on the false index file;
	 * (5) reset the_index from HEAD;
	 * (6) update the_index the same way as (2);
	 * (7) write the_index out to the false index file;
	 * (8) return the name of the false index file (still locked);
The net effect being that the index will match the work tree for the
listed paths when the operation is over, while other files are
untouched.
-- 8< --
Subject: Documentation: clarify "commit --only" description
>From the current description, one might imagine that "git commit

<pathspec>" bypasses the index completely. Clarify what it does do to the index:

 - paths matching <pathspec> are updated to match the work tree
 - paths not matching <pathspec> are left alone

so readers can have a better idea of what the index represents before and after such an operation.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 I'm not so happy with the wording.  Hopefully this gives the idea...
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 42fb1f5..6bb3eff 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -191,9 +191,10 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
 --only::
 	Make a commit only from the paths specified on the
 	command line, disregarding any contents that have been
-	staged so far. This is the default mode of operation of
-	'git commit' if any paths are given on the command line,
-	in which case this option can be omitted.
+	staged so far.  The state of other files in the index is
+	preserved and will not affect the commit.  This is the
+	default mode of operation of 'git commit' if any paths are given
+	on the command line, in which case this option can be omitted.
 	If this option is specified together with '--amend', then
 	no paths need to be specified, which can be used to amend
 	the last commit without committing changes that have
Jeff King· Oct 15, 2010, 19:48 UTC · re: Jonathan Nieder · lore

Re: Can I checkout a single file without altering index?

On Fri, Oct 15, 2010 at 02:32:52PM -0500, Jonathan Nieder wrote:
Show 21 quoted lines
> > git commit -o|--only, which is the same as "git commit <paths>". Of
> > course it still uses an index, to create the tree, but it uses a
> > temporary one based on HEAD instead of the current index contents.
> 
> Ah, it's stranger than that.
> 
> 	 * A partial commit.
> 	 *
> 	 * (0) find the set of affected paths;
> 	 * (1) get lock on the real index file;
> 	 * (2) update the_index with the given paths;
> 	 * (3) write the_index out to the real index (still locked);
> 	 * (4) get lock on the false index file;
> 	 * (5) reset the_index from HEAD;
> 	 * (6) update the_index the same way as (2);
> 	 * (7) write the_index out to the false index file;
> 	 * (8) return the name of the false index file (still locked);
> 
> The net effect being that the index will match the work tree for the
> listed paths when the operation is over, while other files are
> untouched.

Well, yeah, it does have to update those files in the regular index. Any other semantics would be insane; the change would appear reverted looking at the difference between HEAD and the index.

With respect to your proposed change:
Show 15 quoted lines
> diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
> index 42fb1f5..6bb3eff 100644
> --- a/Documentation/git-commit.txt
> +++ b/Documentation/git-commit.txt
> @@ -191,9 +191,10 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
>  --only::
>  	Make a commit only from the paths specified on the
>  	command line, disregarding any contents that have been
> -	staged so far. This is the default mode of operation of
> -	'git commit' if any paths are given on the command line,
> -	in which case this option can be omitted.
> +	staged so far.  The state of other files in the index is
> +	preserved and will not affect the commit.  This is the
> +	default mode of operation of 'git commit' if any paths are given
> +	on the command line, in which case this option can be omitted.

I always assumed that "disregarding any contents that have been staged" meant "we will leave unmentioned paths alone". But I don't think it hurts to be explicit. So your change looks fine to me.

-Peff
Neal Kreitzinger· Oct 15, 2010, 18:57 UTC · re: Jonathan Nieder · lore

Re: Can I checkout a single file without altering index?

"Jonathan Nieder" <jrnieder@gmail.com> wrote in message news:20101015184302.GA22990@burratino...

Show 9 quoted lines
> Hi Neal,
>
> Neal Kreitzinger wrote:
>
>> However, there is an option in git-commit to copy files directly from the
>> working-tree to the object-store by totally bypassing the index
>
> What option is this?  I thought "git commit --include" added content
> to the index.
>From the git-commit manpage (1.7.1.2):

"3. by listing files as arguments to the commit command, in which case the commit will ignore changes staged in the index, and instead record the current content of the listed files (which must already be known to git); "

(I haven't tried it myself because to me the index is a key technology of git so I'm not sure why I would want to bypass it.)

v/r, Neal

Andreas Schwab· Oct 15, 2010, 19:02 UTC · re: Neal Kreitzinger · lore

Re: Can I checkout a single file without altering index?

"Neal Kreitzinger" <neal@rsss.com> writes:
Show 6 quoted lines
> However, there is an option in git-commit to copy files directly from the 
> working-tree to the object-store by totally bypassing the index, but no one 
> seems to do this or recommend doing this as normative practice.  None the 
> less, this "exception" in the git-commit manpage does seem to set the 
> precedent, so maybe it is also conceivable to copy objects directly from the 
> object-store to the work-tree by totally bypassing the index.

You can always do "git cat-file blob <object>", though you have to redirect output manually.

Andreas.
-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Junio C Hamano· Oct 15, 2010, 23:22 UTC · re: Neal Kreitzinger · lore

Re: Can I checkout a single file without altering index?

"Neal Kreitzinger" <neal@rsss.com> writes:
> FWIW, my understanding of the index is that it is the middle-man for moving 
> things from your work-tree to the object-store AND for moving things from 
> the object-store to your work-tree.

While there is nothing technically incorrect in the above, it probably is easier to explain/understand why it works in the direction from the object store and to the working tree if you state it this way instead:

  The index is where you build the contents for your next commit.
   - You build your next commit starting from the current commit,
     so when you do "checkout" from the object store, both the
     index and the working tree are populated with the blob.
   - You then modify that state in your working tree, hopefully
     testing, reviewing, and thinking about your change while
     doing so.
   - There may be good changes, not good enough changes, and
     perhaps only for debugging changes in your working tree.  You
     can decide to make commits out of only the good bits, leaving
     others uncommitted.  You add only good bits to your next
     commit, and the command to do so is naturally called "git
     add" (and "git add -p" for add changes to a file partially by
     picking patch hunks).
   - There may be a time where you regret that some changes you
     made to your working tree are not good, and want to start
     over.  You may even do so after you added some changes to
     the index (i.e. your next commit).  By checking the path
     out of the current commit would give you the original
     version of the path both in the index and in the working
     tree file to help you start over.
   - After making that commit, you will keep working to create
     the commit next to that commit you created.  To help you
     work incrementally, the index at that point contains what
     you committed.
 
> However, there is an option in git-commit to copy files directly from the 
> working-tree to the object-store by totally bypassing the index, but no one 
> seems to do this or recommend doing this as normative practice.
This is wrong.  People do this all the time with "git commit $path".
What happens behind the scene is:
 - git prepares a temporary index that matches the contents of the
   current commit;
 - the contents for $path from the working tree is then added to that
   temporary index;
 - a new commit is written out of that temporary index; and
 - the $path is also added to the real index (this is a very important
   detail---otherwise the next commit will lose the change to $path).

Notice that in no step the index is really bypassed. Everything literally goes through the index.

If you want to bypass the index, you can do so with cat-file or show; it just is not a useful operation in a normal workflow of building the next commit on top of the current one, and that is the only reason why there is no option such as "checkout --no-index HEAD~47 path". If somebody can write a convincing use case that shows why it is useful, such an option shouldn't be very hard to add. But I don't think of any. For example, this is not it:

    I start from a clean slate and start working.
    $ git checkout
    $ edit; git diff; compile; test; git add path ;# repeat
    At this point I have some cooked contents added for the next commit
    in the index for path.  But I realize that the contents of that path
    in another branch might be even better.  But I do not want to lose
    the state I arrived at, which might be better than that alternative.
    I cannot decide, so I'll keep that in the index for now.
    $ git checkout --no-index the-other-branch path
    $ edit; compile; test; ...
    case I. yes the other one indeed is better
    $ git add path
    case II. no the other one is inferiour
    $ git checkout path ;# out of index

While superficially this looks promising, this is unwieldy. For one thing, you cannot easily check what you changed anymore, as "git diff path" would show the difference between the index, i.e. a version that was modified in a different way from the current version, and the working tree, i.e. another version that was modified starting from a totally different version in the-other-branch.

Jonathan Nieder· Oct 15, 2010, 23:40 UTC · re: Junio C Hamano · lore

Re: Can I checkout a single file without altering index?

Junio C Hamano wrote:
Show 15 quoted lines
>                                                           If somebody
> can write a convincing use case that shows why it is useful, such an
> option shouldn't be very hard to add.  But I don't think of any.  For
> example, this is not it:
> 
>     I start from a clean slate and start working.
> 
>     $ git checkout
>     $ edit; git diff; compile; test; git add path ;# repeat
> 
>     At this point I have some cooked contents added for the next commit
>     in the index for path.  But I realize that the contents of that path
>     in another branch might be even better.  But I do not want to lose
>     the state I arrived at, which might be better than that alternative.
>     I cannot decide, so I'll keep that in the index for now.
To be a devil's advocate (because I am not convinced yet), here is one:
    I start from a clean slate and start working.
    $ git checkout
    $ edit; git diff; compile; test; git add path ;# repeat
    At this point I have some cooked contents added for the next commit
    in the index for path.  Illustrating the new change is a new test,
    and I want to "test the test" by trying it out against the inferior
    previous state.
    $ git checkout --no-index HEAD path
    $ test; edit test; git diff; compile; test; git add test ;# repeat
    Now one last test run with the improved state
    $ git checkout path
    $ compile; test
    $ git commit

← back to recent threads