Refresh staged files

Go To StackoverFlow.com

20

In git, is there any (simple) way to modify the index so that only changes to files which are already in it are added? It sounds kind of complicated, but what I want to achieve is simple.

Lets say my index looks like this (slightly stripped git status output):

# Changes to be committed:
#       modified:   A
#       modified:   B
#
# Changed but not updated:
#       modified:   B
#       modified:   C
#
# Untracked files:
#       D

Some changes to B are in the index, some aren't. C is not staged at all.

How can I update B in the index (stage its unstaged changes) without adding C?

I.e. I would like for the index to look like this:

# Changes to be committed:
#       modified:   A
#       modified:   B
#
# Changed but not updated:
#       modified:   C
#
# Untracked files:
#       D

In this simple case it can of course be achieved with a simple git add B, but I would like to know if there's a simple answer for the general case. I tried git add --refresh, but if I understand correctly, that only updates stat info.

2012-04-04 07:10
by axelarge
Can you show a real use-case where you'd want to do that? I can't imagine any (when I add a file and than modify it more, it does not automatically mean I'll want to add those changes too, especially when I won't want to add changes in some other files) - Jan Hudec 2012-04-04 08:34
@JanHudec I probably wouldn't need this if I was stricter and touched only those files that should go in the commit (B). However sometimes I get carried away and start making changes that should be in a new commit (C), so I add B to the index. Before commiting I always review diff --cached and sometimes clean something up in B. and that's when I need this. I guess it could probably be solved in another way, say with stas - axelarge 2012-04-04 09:09
My point is, that when you are doing something in file X that should go in commit B and get carried away and do changes that should go in commit C, some of those changes are often again to file X. In which case you want to add -i individual hunks manually and not just re-add file X. Obviously if you get carried away, you probably noticed something around the point you were changing, which is why it's unlikely the extra changes don't touch the files the fist set does - Jan Hudec 2012-04-04 09:39


26

The following command will update the index to contain the other changes in B that has not been staged yet:

git update-index --again
2012-04-04 16:56
by ralphtheninja
Ah, way better than my method - torek 2012-04-04 19:16
Perfect! That's exactly what I neede - axelarge 2012-04-05 08:33


1

I don't know of a completely trivial way to do this, but:

git status --porcelain

will show file B (and only B) as state "MM", so:

git status --porcelain | grep ^MM | cut -d' ' -f 2

will produce a list of such files.

There's no harm in "re-adding" A, though.

You can also use git diff-index --cached --name-status HEAD. (Might need this if your git is too old to have git status --porcelain.)

2012-04-04 08:18
by torek
Thanks, I didn't know about --porcelain for status - axelarge 2012-04-04 09:14
It's currently the same as -s / --short, but promises to continue to be machine-parse-able, which is important if you stick it in some script. :- - torek 2012-04-04 09:28
I tried git status --porcelain | grep ^[AM]M | cut -d' ' -f 2- | xargs git add, but it fails with filenames that contain spaces. I guess this could be seen as another question, but maybe you can help? With xargs -0 it doesn't work at al - axelarge 2012-04-04 09:54
@axelarge: add tr '\n' '\0' in the pipe and then use xargs -0hroptatyr 2012-04-04 10:06
Ugh, spaces. I deliberately ignored them above. :-) Without using -z here, git encodes spaces with quoting. This works for at least one case: git status --porcelain | grep ^MM | sed 's/...//' | while read var; do eval git add $var; done but I don't know if it will work for all (using eval like this does not give me warm fuzzies...) - torek 2012-04-04 10:07
@hroptatyr: that won't quite work because git prints "E F" (with the double quotes) for the file named e-space-f. git status --porcelain -z can be used, but then the simple grep fails - torek 2012-04-04 10:10
Oh, also, watch out when using square brackets as in ^[AM]M since the shell will then attempt to expand them to match a file named ^AM for instance. (Just put quotes around the grep expression. - torek 2012-04-04 10:12
@torek Thanks for all the help. This seems to work, do you see any problems? (I'm not exactly an expert on all the unix tools) git status --porcelain | grep '^[AM]M' | cut -d' ' -f 2- | sed 's/ /\\ /' | xargs git addaxelarge 2012-04-04 10:16
I was surprised at first that what amounts to git add E\\\ F works to add the file whose shell-level name is just E\ F, but it's presumably because of the fnmatch call git uses. You can also git add \\A even if there is only a file named A (not \A). But, I'd leave out the last sed, it's not needed (try using xargs ls -l instead of git add for instance). But, this does not work with a file named ". (Using | while read -r var; do eval git add $var; done works with the file named ". Not that I like using eval. - torek 2012-04-04 10:39
Ads