• Servers and Tools

The Working Tree

From the class:  Inside Git

Directory. So far, our git database has five objects in it. It has three blobs, each of which has some content, and two trees, each of which serves as a directory structure pointing to these blobs, and giving them file names. Then, inside of the index file that gets created for us automatically by GitHub, we have three entries, each representing one of the files that we've created. And we can take that index, like I showed you in the last video, and write it to a tree, which becomes a new object in our database.

So far, we have nothing in our project directory. It's just empty. We've been working directly with a git database. And what I want to show you in this video is how we can bring all of these files that we created in the git database down into our actual project. First, some vocabulary-- this folder right here is referred to as the working directory. I'd been calling it so far a project folder. But if you see working directory, it means the project folder.

So what we want to do next is to get all of these things in the index down into our Working Directory. And we can use a simple command to do that, called Check Out Index-- checkout-index. And I'll give it the All Flag, which says just download, or check out, everything that's in the index, and make them files in my local project folder.

Now I'll press Enter. And if I say ls with the al flags now, notice that we actually have three real files now that are in our project folder. So we're getting a little bit closer now from the git database to what we actually see in our projects. Let's make sure that we weren't duped by actually looking at the contents of these files. So 1.txt has the content 1cat. 3.txt is 3. All right, looks like we're good to go here.

So what we've just done is we've taken git database objects and made those into actual, concrete files in our working directory. And so far, we've only been using low-level get commands. We haven't used anything like the commands that you're probably used to using when you play with get.

And we haven't done anything with commits yet, or any of the higher-level concepts. But hopefully you're starting to get an idea of how git actually stores data, and the relationship between that data and what we actually see in our project folder.

Currently what's in our working directory and what's in the index are the same. They both represent these three files, 1, 2, and 3. Let's go ahead and make a change to one of these files. I'm going to echo out 3 version 2 to the file 3.txt, which will change its contents from 3 to 3 version 2. Let's just double check.

OK, now I'm going to show you an option of ls files that will show us which files have changed in our working directory, as compared to what's in the index. I can add the -m option. And that shows me that 3.txt-- that file has changed from the version that's in the index.

If you want to learn about these different options of ls files, or any of the git commands, you can say man and then git- and whatever the command is-- in this case ls-files. And in this man page for ls files, if I scroll down using the J key a little bit, you'll see these options. We can look at which files have been modified from the index, deleted, or others, showing untracked files.

So these are files that are not in the index yet. Let's update our index with the change to the text file 3.txt. I'll use the same low-level plumbing command that we've been using to update the index previously-- update index. And this time I'll pass it the path to the file name, 3.txt.

Now our index is updated. And if we say git-ls-files dash-m, it should just be empty. Because the index now is the same as what we have on our working disk. But we haven't written a tree, a new tree, from the index yet. It's just stored in the index so far. And to do a new tree, to write a new tree, we can use the Write Tree command, just like what we did previously.

And we get back a new SHA-1 hash, representing the new tree that was written out to disk. So we've just added a new object now to our git database. And let me show you what that looks like. We can use the git-cat file command again, to take a look at the contents of our new tree. I'll just paste in the first four characters of the code, the SHA-1 has that we got back previously. And this tree points to three files.

But there's something a little bit strange going on here. If we look at the SHA-1 hash of 3.txt, this is actually a new SHA-1 hash. It's completely new from the old one that we had. So git actually made another object in our database for the changes in 3.txt, an entirely new object.

If you want to see that, we can take a look at the old object. I'm going to say git-cat file. Or we can even use git-show here. And the old object hash is 2bdf. I just have that in my notes. And this is the contents of the old blob object that was in the database.

But it's still there. It doesn't get deleted. It's just an old object. And now this new tree points to a different object. Let's type in the first couple of characters-- dd4b. And this is our version two of that file.

So both of these blobs are actually stored on disk. And we can see that very clearly, by looking into the objects directory again. So I'll say git-- or find git objects. And we'll filter by file. And see if you can look in that list, and find the two files.

So we've got the old one, which is 2bdf. That's right here. And then the new one is dd4b. So it's right here. So this is the first version of 3.txt-- or actually, just the content 3. And then this is the new version. So it says 3 version 2.

So one of the things that you'll hear a lot about git is that git creates snapshots of content. And this is what that means, is that it's actually creating brand new objects in its database for changes.

All right, we've gone one way, from the index down to our working directory. But let's go the other way. Let's create a file in our working directory, and get it into the index, and then write it to a new tree. And let's go one step further. Remember we talked about trees can have sub trees that can point to other trees?

Let's go ahead and create a directory called lib. And then I'm going to create a new file. I'll just call it 4, and echo that to lib4.txt. But now, in my working directory, I have this new folder called lib. And it's untracked in our index. So we can say git-ls-files, and use the other option, to say, what is not in the index, currently? And that is lib4.txt.

So the first thing we need to do to get it into the index, or to write it to a tree, is to add it to the index. And I can use the Update Index command again. This time I need to pass the add flag, because we're adding something new. And we're going to add to lib4.txt file.

Let's take a look at the index files now. And notice, it's been added as a new entry. And it has this directory-like name, so lib/4.txt. And let me point out something else here. Notice that this entry has a SHA-1 hash.

So when we add this file to the index, git actually does write it to a blob object in the database. So this does have a file in the Objects folder that corresponds to the content of this file. But it's not pointed to by anything yet. Because we haven't created a tree that points to it.

Let's go ahead and do that now. And we'll do it the same way we've been doing it all along, is I'll say git-write-tree. And that will give me back a new tree, which we can look at by using cat-file.

And now this tree points to something interesting, that we haven't seen before. It actually points to another tree. See this first entry, right up here? It points to a tree. The tree has its own SHA-1 hash. And the name is lib. So this corresponds to the diagram that I showed you in the last video.

So we've got these three files, and this other subtree, called lib. And we can take a look at that subtree, by using cat-file again, and typing in the first few characters of the SHA-1 hash. And this tree just has one entry, which is a blob. And that points to our file 4.txt.

And the SHA-1 hash here is the same as the SHA-1 hash up here. Notice, these two objects are the same. So if we were to go into the database, and take a look at the files, you would see that this actually has its own object. Let's just do it, just to make sure that you see it. Find git objects. Filter by file. And just look in there for 85016. You probably found it before I did.

Here it is, right in the middle-- 85106. So this is our new object in the database, that corresponds to the content in 4.txt. And now it's pointed to by an actual tree, that has its own SHA-1 hash.

Let's wrap up by taking a look at a quick diagram that illustrates what we've just seen. On the far left, we've got our working directory. That's where we're going to work in our project. And from the working directory, we can send files up to the index.

And we can also pull files back down from the index, and recreate directory structures and files. And from the index, we can write trees out to the object database, which creates a new tree, with its own SHA-1 hash, and a file, that's in that objects folder of git. That's what comprises the database.

Now you might be asking, this is all good, but what about commits? That's what I'm so used to working with with git and source control. So next up I'm going to show you how commits fit into this picture.