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.
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
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
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
.)
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
tr '\n' '\0'
in the pipe and then use xargs -0
hroptatyr 2012-04-04 10:06
-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
"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
^[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
git status --porcelain | grep '^[AM]M' | cut -d' ' -f 2- | sed 's/ /\\ /' | xargs git add
axelarge 2012-04-04 10:16
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