Reputation: 21
I'm finally learning git and I'm a bit confused. From what I have read, and probably misunderstood, you have to "git add" after making changes to a file (saving the file locally in your ide?) before then "git committing".
When I "git add" all my files in the working directory, make changes and save them in the ide, then "git commit", all the changes are committed just fine. Why do I need to restage with "git add" between the save and commit? It doesn't seem to make any difference and I'm confused why I've read that you need to given that it seems to make no differences. Apologies if this is a duplicate, I did look and couldn't find an answer to my question.
Oh also, I would understand if I were making a new file, as this would need to be added with "git add" as it isn't already known, but I don't understand when I'm changing files I've already added.
My test for this is running "git add" changing a file and saving it, trying a commit to see if it registers changes without a new "git add", which it does as it outputs a message informing of the changes I have made. I must be missing something in my understanding. Thanks for any help.
Upvotes: 2
Views: 165
Reputation: 490168
Some IDEs do the git add
for you. Yours may be one of these—we can't tell since you did not name it.
Some IDEs don't do the git add
for you. In this case you must do it yourself.
Oh also, I would understand if I were making a new file, as this would need to be added with "git add" as it isn't already known, but I don't understand when I'm changing files I've already added.
It sounds to me like your mental model matches Mercurial's actual model. In Mercurial, you use hg add
to tell Mercurial: this file should be in commits. From then on, hg commit
uses the version of that file in your work-tree to make the new commit.
(The work-tree is where you do your work. This is as opposed to the commits, which are read-only: you literally can't change files stored in commits. They're also generally highly compressed, and in a form useful only to the version control system. This is true in both Mercurial and Git.)
Git is different from Mercurial. When Git makes a new commit, Git does not use what is in the work-tree. Git instead uses something it calls, variously (depending on who is doing the calling), the index, the staging area, or even the cache. This particular tactic seems wacky and crazy to anyone who has used Mercurial, or, well, just about every other version control system, but that's how Git works.
When Git extracts a commit, it copies the commit's contents into both the index and the work-tree. The version of each file in the index matches the version stored read-only in the commit; but the copy that is in the index can be overwritten. Git then uses the index copy (which now matches the commit's copy) to make the work-tree copy, in its normal, uncompressed format so that you can work with it.
When you run git add file
, Git copies the normal, uncompressed work-tree file back into the index (aka staging-area). That replaces the previous version of that file, and git commit
will commit the index version, which now matches the work-tree version.
Because Git makes commits from whatever is in the index, you—or your IDE—must continually copy any modifications made in the work-tree into the index. The fact that the index version is already in the special, Git-only, compressed format makes git commit
go very fast—at the expense of requiring all these extra copy steps. In a big repository with a lot of files, this actually makes a huge difference: hg commit
can take seconds while git commit
is nearly instantaneous.
(In a small repository, Git's fanciness is mostly just annoying. However, you can play special tricks with the index, so as to commit something that's different from both the previous commit, and what's in the work-tree! This is actually tremendously useful in some cases. It's also terribly confusing, and not something to do casually if you can avoid it.)
Upvotes: 4