11

I basically know the difference between a git add which means "I want to add this file to my next snapshot" and git commit which means "take the snapshot".

However, when I run git add file1 and then removing file1 from my working directory and then run git commit it will still works. Somehow the snapshot was taken while adding and not not while commiting. Am I right?

0

3 Answers 3

8

git commit takes the snapshot by

  • looking at the index (where you have added the file),
  • not by looking at the working tree (where you go on modifying stuff, including adding or deleting files)

See "What's the difference between HEAD, working tree and index, in Git?"

In your case, after deleting the file (but after adding it to the index), a git status would give you:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   go.mod

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    go.mod

The file is both:

  • ready to be part of the next commit
  • locally deleted

A git restore -- <myFile> is enough to restore it locally.


The working tree (or working directory) is the tree of actual checked out files.
The working tree normally contains the contents of the HEAD commit’s tree, plus any local changes that you have made but not yet committed.


The idea is to prepare your next commit, instead of blindly putty all your current modification into one giant commits.
It is better to make small coherent commits instead of a giant one, for getting a logical history, and making future git bisect easier.

You can even stage (add to index) part of a file (interactive staging)

The OP adds:

Imagine that commit does the work of both the actual commit and add.
Let's call it the imaginary commit.
You can still do this little by little work using the imaginary commit

First: that command (which adds all and commit) does exist:

git commit -am "Let's add everything"

Second, to do "little by little", you must use git add, then commit.
A commit takes everything in the index.

Sign up to request clarification or add additional context in comments.

7 Comments

Is the working tree = the working directory ?
@Giant8 Yes, those terms reference the same concept
Thanks ! I am still wondering however what's the real utility to have two different commands, why not just have only one that do both at the same time. Is there some useful cases when someone wants to use add without commit later ?
@Giant8 I use it all the time. When you do a lot of modification, the last thing you want to make is one giant commit. You add only a small coherent subset, make a first commit, add the rest, little by little, making small commits along the way. You can even add parts of a file instead of the all file, if you have made multiple modifications inside the same file. See "interactive staging": git-scm.com/book/en/v2/Git-Tools-Interactive-Staging
@Giant8 I have edited my answer to address your comment. "little by little" means first adding that "little" in the index, then committing.
|
5

Actually, there is something missing from what you know.

You actually have two copies of that file when you have added it. You have the working tree copy, which is the normal file system copy that you see and edit with normal text editors and whatnot.

But, additionally you have a copy in the index. git add copies the file and its contents from the working tree into the index. This is where the actual snapshot of that particular file is made.

When you afterwards issue a git commit, the index is stored into a commit. What is, or is not, in the working tree (aka on disk) at this point is rather irrelevant. The index is all that matters.

This is why you see that the file is still being added. It was copied to the index with git add, and even if you subsequently removed it from disk, git commit used the index as the source of the commit.

The upshot of having a separate index which makes up what the next commit is going to be is that you get to decide what your next commit is going to contain, as opposed to just "all the things on my disk at the moment". Good git tools even lets you copy files with only parts of their changes into the index, so that if you made 2 or more changes to a file you get to decide if all the changes to that single file go into the next commit or just one or a few of them.

7 Comments

The working tree is another name for the working directory, am I right ?
Yes, though I believe the established git terminology is "work tree". But basically it is your files and folders on disk, part of the normal operating system workflow, as in what you would have if you simply ignored the entire git part completely. "I believe" means I'm not 100% sure, however.
Thanks ! I am still wondering what's the real utility to have two different commands, why not just have only one that do both at the same time. Is there some useful cases when someone wants to use add without commit later ?
@Giant8 No, but the opposite. You might commit without adding all the changed files, because you have actually done two or more separate changes. For instance, you might have refactored a class to better separate the responsibilities in it, as well as adding support somewhere else for reading data from a database. Those two things might be good to commit as two commits, with appropriate comments, instead of lumping them together. So you might want to add only some of the files before the commit, and then add the rest afterwards, and then so on.
If your imaginary commit just commits the current state of your working folder, then sure, you just need to make your changes in smaller sections and commit inbetween. You can do a git commit -a ... which will automatically add all changed files before the actual commit, in essence combining git add and git commit into one command.
|
2

You are absolutely right. Not only that, but the file is kept as it is at the moment when you add it. If you later change it and then commit, it's saved in the revision as it is at the moment when you asked for it to be added, not the current state. Same things happen for files that are modified (just in case you think it only works for new files). If you commit a file and you modify it, git will only persists it with the new content for the following revisions if you add it.

8 Comments

So what's the real utility to have two different commands, why not just have only one that do both at the same time. Is there some useful cases when someone wants to use add without commit later ?
Actually? Yes.... You can modify dozens of files, and then you get to choose what you really want to commit. What's there to complain about? The index (what will be used for the actual revision when you commit) is one of the wonders of git. Just in case, you can always use git commit -a, but I (for one) am not fond of it. I like to select the pieces that I want to commit.
There's one more workflow that this allows. You can add stuff that you think is ready... and then you get the luxury of modifying files to see if you can improve them. If you do improve them, you add again.... if you don't, well, no need to do anything else, just commit (which will use what you had added before).
My advice: give yourself some time to use git extensively so that you get to see all the different crazy situations that coding will get you through and see how git is able to cope with them. Given enough time, it will all make sense.
All objects that are put in git's DB get an ID (currently using SHA-1 but git will slowly move to SHA-256 over time... process has already started). When you add the file, the content is put in the object DB and an ID will be used to point to it, the file is also added in the index (probably under a tree object so some tree objects will also be created, each with their own IDs). When you commit, a new revision object will be created and it will also get its ID at that moment.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.