This post is part of a series:
In the previous post, we have learned about the key concepts that one should probably know when working with Git. And in this post, we are going to see how we can actually use it to inspect the history of an already existing project.
Introduction to Git
If you haven’t already downloaded Git, then go ahead to the Git website and download it for your respective operating system and follow the installation instructions.
If you have done that, then you can open “Git Bash” which is included in the download for Windows (which is what I am using). Or if you are on Linux or MacOs, you can open the terminal.
See slide 1
So now, let’s first check if Git is actually working. Therefore, let’s simply type “git” and press enter.
See slide 2
If it is working, then this will list common Git commands together with a short explanation.
See slide 3
To learn more about the individual commands, we can type the respective command together with the “--help” option. So, let’s do that for “git init”:
See slide 4
This will open the whole manual page for the command.
See slide 5
If we want some more concise information right in the command line, then we can use the shorthand option “-h”:
See slide 6
And to see what version of Git we currently have, we can simply type “git --version”.
See slide 7
Introduction to the Project
Okay, so that was a short introduction on how to generally interact with Git. So now, let’s see what a version-controlled project actually looks like. Therefor, we will download one from my GitHub account.
See slide 8
This project contains the code for a command-line-based Tic-Tac-Toe game. To download it with Git, we click on the green “Clone or download”-button. This will open up a drop-down menu. Here, we then click on the “copy-to-clipboard”-button to copy the URL of this project.
See slide 9
Now, we are ready to download it using Git.
To be able to do that, we will learn about our first Git command, namely “git clone”. By passing the URL of a project to this command, we can download the respective project. Before we do that, however, let’s first change the directory and go to the desktop.
See slide 10
By running the above command, we download the project folder to our desktop. So, let’s do that and then have a look at the folder.
See slide 11
As we can see, the project folder contains two Python files, namely “game” and “helper_functions”. Then, there is also a README file and a file called “.gitignore”. And finally, there are two folders named “supporting_materials” and “.git”.
We will have a closer look at all those things during the tutorial. But now, let’s first check out the game itself. Therefore, let’s go into that folder and run the “game.py” file.
See slide 12
First, we are asked how many rows and columns the game board should have.
See slide 13
We are going to stick to the traditional size of a 3x3 board. After that the board is printed and player X is asked what position he/she wants to play.
See slide 14
We are going to choose position “1, 1”. Then, the board is printed again. But this time with player X’s choice depicted. Then, it’s player O’s turn.
See slide 15
This way, the game proceeds until there is a winner or no more position is left to play. And then, the game asks the player if he/she wants to play again.
See slides 16-19
So, that’s what the game looks like. And the code, by the way, is based on a Python tutorial by Sentdex. So, if you want to know how the code works in detail, you can check out that tutorial. I just changed it a little bit to suite my purposes.
Looking at the Commit History of the Project
And now that we have seen what the actual project itself looks like, let’s inspect its commit history. So, we are going to have a look at how the files in the folder changed over time. To do that, we are going to use the command “git log”.
See slide 20
If we run the command, then we can see the different commits of this project.
See slide 21
And here, each block is one particular commit and the most recent one is depicted at the top. There, we can see its hash, author, timestamp and commit message. Additionally, in the parentheses, we can see that the master branch is at this particular commit and that HEAD is pointing at master. So, the project is currently in the state of this commit. And then, we can also see that the master and HEAD of the remote repo are also at this particular commit.
And if we now look at the end of the output of “git log” command, then we can see that there is a colon at the end.
See slide 22
This indicates that there are even more commits. To see them, we can either use the “down arrow key” to expose the lines one by one, or we can use the “space bar” to expose several lines at once. So, let’s also have a look at the remaining commits.
See slide 23
At the bottom, there is the very first commit of the project called “initial commit”. This means that we have reached the end of the log, indicated by “(END)”. To exit the log, we need to press “q”.
So, that’s what the commit history of the project looks like. And since it is a little bit difficult to get an overview of the project in this way, we can also print out the log in a more precise way if we use a specific option for the “git log” command. Namely, if we type “git log --oneline”, then each commit is simply depicted in one line.
See slide 24
So here, it only shows abbreviated versions of the hash and then the commit messages (as well as “HEAD” pointing at “master”, “origin/master” and “origin/HEAD”). And this way, it is a little bit easier to get an overview of the project as a whole.
Traversing the Commit History of the Project
So that’s how we can have a look at the history of the project. Let’s now see how we can traverse that history. So, how we can revert the project back to different states, i.e. commits.
Currently, we are at the most recent commit. So, let’s now revert the project back to the state of the fourth last commit (“Merge branch ‘valid_move’”). By doing that, the files in the folder will be changed back to what they looked like at that particular commit. To see the difference let’s first look again at the folder in its current state.
See slide 25
And now, let’s revert the project back to the fourth last commit. Therefore, we need a new command. And it is called “git checkout”. This we simply use together with the hash of the fourth last commit.
See slide 26
So, let’s run this command:
See slide 27
Now, Git says that we are in “detached HEAD” state because we have checked-out the commit directly (and not a branch). So, let’s have a look at the folder again.
See slide 28
As we can see, the “supporting_materials” folder is now gone (the “__pycache__” is now there since we ran “game.py” earlier). And that’s because at the fourth last commit, the folder apparently wasn’t created yet. So, let’s look at the history, i.e. log, of the project again.
See slide 29
As we can see, the “HEAD” is at the commit “Merge branch ‘valid_move’”. But where are all the other commits that came after that? They are still there, but “git log” doesn’t show them by default. And that’s because of the “reachability” concept. Namely, “git log” only shows the commits that are reachable from the currently checked-out commit.
But “git log” has an option that allows us to see all the commits that we could potentially reach based on the most recent commit, namely “--all”.
See slide 30
This again, shows all the commits that we have for this project. And we can see, that “HEAD” is at the fourth last commit and “master”, “origin/master” and “origin/HEAD” are still at the most recent commit.
And if we look at the commit messages, we can see that the “supporting_materials” folder was only added at the most recent commit. That’s why, at the currently checked-out commit, it doesn’t exist in our project folder.
Investigating the Difference between different Commits
So that’s how we can use “git checkout” to traverse the history of the project and revert the folder back to the state of different commits.
And now, let’s see how we can actually check what the differences between particular commits are. So, what changes were introduced in the files from one commit to the other. And the commits that we are going to compare are the fourth last and third last.
See slide 31
If we just look at the commit messages, we can see that, at the third last commit, the player names were changed from “1” and “2” to “X” and “O”. This should mean that at the commit, which we have currently checked out, the players should still be called “1” and “2”. So, let’s run “game.py” again to see if that’s really the case.
See slide 32
And as we can see, the game board looks different than before and the players are “1” and “2” and not “X” and “O”. So now, let’s see what the actual differences are between those two commits.
For that, we need the command “git diff”. And to that, we simply need to pass the hashes of the commits that we want to compare.
See slide 33
So, let’s run this command to see what the actual changes in the code are so that we can use the green “X” and the red “O” in the game instead of “1” and “2”.
See slide 34
And looking at the text in the bright, white color, we can see, there are two changes. One was made in the “game.py” file and the other in the “helper_functions.py” file. Let’s first look at the changes in the “game.py” file.
Here, the lines that were removed from the fourth last commit to third last commit, are depicted in red. Whereas, the lines that were added, are the depicted in green. So, as we can see, the integers “1” and “2” were basically just replaced with the strings “X” and “O”.
So now, let’s look at the changes in the “helper_functions.py” file. Here, there were some more changes. First, an import statement was added. And then, the functionality in the “show” function was changed so that not just the “row_index” and the “row” are printed but the “row_index” and the “colored_row”.
So, that’s how we can use “git diff” to see the differences between different commits. And now, let’s finally revert the project back to its most recent state. Therefore, let’s first print out the log again.
See slide 35
So now, let’s check-out the most recent commit. This time, however, we are not going to use the hash of the commit. Instead we are going to use the master branch since it is pointing at the most recent commit.
See slide 36
If we run the above command and print the log again, we can see that the “HEAD” is at the most recent commit and it is pointing at “master” again.
See slide 37
So, accordingly, the “supporting_materials” folder is again in the project folder. And the players are called “X” and “O” again in the game.
See slide 38
And with that we have now seen how we can inspect the history of an already existing project. And here are the commands that we have used so far:
See slide 39
So, let’s now see how we can actually create such a history in the first place. So, how we can create commits. And this will be the topic of the next post.