Reputation: 1591
I have many files that are already added to the index but I would like to commit only some of them AT FIRST because the review tool works on commits. If I simply do a git commit, I think I will get ALL the files. I think I can do: git commit file1 file2 file3 and if this is true, I would like to be able to store a very long list of files in file and specify this as input to the commit command. Alternatively, I would like to be able to commit many times with a single commit id. I do not want to unstage some files because there are hundreds of files in the index, only some of which are important to be reviewed.
Is there a safe way to force this to happen? Once that is done, I will then do a commit to get the remaining files, if possible.
EDIT: Bottom line, yes you can specify some subset of staged files, a partial commit. But in the case of a merge which caused many files to change and be staged and only some of which I wanted to be committed for review (the rest later) you can't do this; Git will not allow a partial commit during a merge. If I am wrong, I am sure someone will let me know.
EDIT: I attempted the "xargs" (as suggested by Edmundo) solution and got the error: fatal: cannot do a partial commit during a merge.
Upvotes: 0
Views: 517
Reputation: 488183
As both phd and Edmundo answered, yes, you can do this, but you need to be aware of how Git actually makes commits.
The normal, standard setup for Git is that there are three copies of every file associated with the current commit:
HEAD index work-tree
----- ----- ---------
file1 file1 file1
file2 file2 file2
: : :
fileN fileN fileN
The copy in the commit (HEAD
) is read-only: it can never be changed. The copy in the index is read/write, but otherwise stored in a special Git-only format. The copy in the work-tree is read/write and is stored in the normal everyday form that your computer uses for files.
When you run git add
, Git copies the work-tree version of a file into the index. Let's say you changed file2
somewhat:
HEAD index work-tree
----- ----- ---------
file1 file1 file1
file2 file2 file2*
: : :
fileN fileN fileN
The asterisk here means that the contents of this version of file2
are different.
Running git add file2
copies file2
from the work-tree into the index:
HEAD index work-tree
----- ----- ---------
file1 file1 file1
file2 file2* file2*
: : :
fileN fileN fileN
(Aside: note that running git reset file2
copies file2
from HEAD
into the index, removing the change from the index while leaving it in the work-tree.)
When you run an ordinary git commit
, Git packages up whatever is in the index right now and makes the new commit using those files. So if you have modified file2
, then copied the new file into the index, then run git commit
, you get the modified file2
in the new commit. The unmodified file1
, file3
, ..., fileN
also go into the new commit.
When you run, e.g., git commit file1 file2
, though, Git does something special.
Let's make a change to file file3
but not run git add
yet.
HEAD index work-tree
----- ----- ---------
file1 file1 file1
file2 file2* file2*
file3 file3 file3*
: : :
fileN fileN fileN
If you run git commit file3
now, for instance, Git starts by copying something into a temporary index.
There are several things Git could sensibly copy here, to get the starting point for the temporary index. What it actually uses depends on flag arguments:
git commit --include file3
: Git copies the existing index to the temporary index. This gets you file1
, file2*
, file3
, and so on. Note that we get the new file2
here, not the old one.
git commit --only file3
: Git copies the HEAD
commit to the temporary index. This gets you file1
, file2
, file3
, and so on. Note that we get the old (HEAD-version) file2
here.
Next, Git adds the files listed on the command line. This replaces the temporary index's file3
with file3*
.
Now Git makes the commit, using the temporary index.
Last, Git copies some things from the temporary index back into the regular (ordinary) index. Specifically, it copies back all the files you listed on the command line—so file3*
goes into the regular index.
What phd is referring to is the use of git add -p
, git reset -p
, or the ability to do:
$ make-change-to file2
$ git add file2
$ make-different-change-to file2
Now you have something we might describe as:
HEAD index work-tree
----- ----- ---------
file1 file1 file1
file2 file2* file2†
: : :
fileN fileN fileN
That is, there are now three different versions of file2
active all at the same time: the original unmodified HEAD
version, the first modified version stored in the index, and the second modified version stored in the work-tree.
If you git commit file2
, Git will make a new temporary index, copy the work-tree file2†
version into that temporary index, commit from the temporary index, and then copy the temporary index file2†
file over the regular index file2*
file. The effect is that you lose the middle version entirely.
Upvotes: 0
Reputation: 94483
I think I can do: git commit file1 file2 file3
Yes, but you must understand that git will ignore staged hunks and commit these files wholly. This is important if you staged parts of files using git add -p
.
Alternatively, I would like to be able to commit many times with a single commit id.
Impossible. Every time you amend a commit its SHA-1 id changes. But if you use gerrit for review it doesn't matter: gerrit appends its own id to commit message on the first commit to link amended commit to the same review; do not remove this id when ammending the commit.
Upvotes: 2
Reputation: 30212
If you have the list on a file, you could use xargs to get them to be passed as the parameters of the git commit: cat file-of-files.txt | xargs git commit -m "Here's a few files to be committed"
Upvotes: 2