Introduction [🔗]
In this tutorial, we’ll learn how to use Git to keep track of changes to text files over time. The steps presented here represent just one way to use Git – a solo workflow, in which the files live on your personal computer and are never intended to be shared with or edited by other people.
Setting up a lil journal [🔗]
Make a new folder on desktop called my-journal
, and inside it make a new text file called readme.txt
. You’re going to want to use a plain-text editor for this task, which differs based on your operating system:
- Windows/WSL: Use Notepad, which you can open from the Start menu
- MacOS: Use TextEdit in plain text mode, which you can open by hitting
Command + Space
and typingTextEdit
(one word). Once you’ve opened TextEdit, hitCommand + Shift + T
to switch to plain text mode.
Type out some info about yourself, like this:
Name: Naomi Alterman
Favorite Food: Pizza
Favorite Animal: Bunnies
Save that file as readme.txt
in your my-journal
folder.
At this point our my-journal
folder is just a normal file folder, with normal files. Let’s turn it into a git repository so we can track changes to those files over time!
Turning our journal folder into a repository [🔗]
Open the Sublime Merge application, which is a graphical utility to work with Git repositories. It’ll look like this:
Click the “New Repository” button, and in the dialog window that opens up navigate to your my-journal
folder. Select it. Sublime Merge will turn the folder into a git repo, and present a screen to us that looks like this:
The window is laid out like this:
- The central region is a timeline, showing the ordered history of all file changes as grouped into named snapshots called commits (we’re “committing” to a given version of the file at that point in time).
- The right region contains a summary tab and file tabs. If we select a point in the timeline, this tab will show us the differences between files at that point and the commit immediately beforehand in time. These differences are called the diff.
- The left region contains several different lists, most of which we’ll ignore for now. Throughout these tutorials, we’ll learn what branches and remotes mean. If you click the
Files
tab, you’ll see all the files in the repository.
Making our first commit [🔗]
Let’s make our first commit, in which we’ll mark the initial version of our user profile.
We’ll start by staging the changes, which indicates to Git that we want to include them in the next commit. Expand the list of “Untracked Files” (1), and then readme.txt (2). Note how this displays the contents of the file in green: these are the changes in the file since the last commit, also called the diff. Since it’s a new file, and this is our first commit, all of the file text is new and thus highlighted in green. To include this data in our commit, click the ‘Stage’ button (3):
The summary tab will change, showing that instead of there being “untracked files”, now there are “staged files”. Write a commit message in the text box at the top of the summary tab indicating conceptually what these changes include (1), then click “Commit 1 file” (2):
Our commit, and its message, will now appear in the center part of the window. If we select it with the mouse, we can see the changes to our files recorded at that point in time (in this case, the addition of our readme.txt
):
Notice the line in the summary labelled Commit Hash
: the string of letters and numbers on this line, called a hash, serves as a unique name for this commit (that is, this set of changes to our files). Git tools (and git users) will often use commit hashes as “names” for specific points in the timeline. Insetad of including all of the hash, it’s often sufficient to just include 6 or 7 characters from the beginning (left side) of the hash. For example, the selected commit in the screenshot could be referred to as commit 6725ed
.
Using commits to record changes [🔗]
Let’s change our profile. Go over to your text editor and make a few changes:
- Add a new line in the middle of the file and specify your favorite song.
- Replace your favorite animal’s name with its taxonomic name (you may have to google it)
My profile now looks like this:
Save the file and go back to Sublime Merge. Click the “unstaged file” entry at the top of the timeline to see your changes to the file in the diff panel:
Click ‘Stage’ next to readme.txt to accept the changes. Then type a commit message out and commit the changes. Now we’ll have two commits in our history:
Let’s add another file. Make another file in your journal folder called recipe.txt
and paste your favorite recipe into it:
Add a new line to readme.txt
mentioning it:
Make sure to save all those files, and then return to Sublime Merge. You’ll see the changes to your readme.txt
file, but the brand new file is currently hidden. To add it to the repository, expand the “Untracked Files” section at the bottom:
Click the “Stage” button on both readme.txt
and recipe.txt
to include both of them in our next commit:
Now type out a commit message, and make the commit!
Now we have a journal folder containing our personal profile and our favorite recipe. We can click different commits in Sublime Merge’s timeline view to see how those files changed over time:
To view the difference between two commits that aren’t next to each other in time, hold the control key (or on MacOS, the command key) and select the two commits you want to compare. Notice the Diffing from
line in the summary, indicating the point in the timeline we’re “comparing” against. Put another way: by selecting multiple commits, the diff view will show us all of the changes that happened between those points in the timeline:
Time-travelling with check-outs [🔗]
Sublime Merge will let us browse the diffs at various points in time, but what if we want to open previous versions of our files in other applications, like Photoshop or VSCode?
We can use Git to “time-travel” all of the files back to a previous point in time by checking out a previous commit. In general Git jargon, the term check out means to make the contents of a repository match a specific point on the timeline:
📖 “Check out” - verb
- To “check out a commit” means to make all files in the repo reflect their contents at that commit’s point in the timeline.
- To “check out a file” usually means to return a file to its present-day contents
Anyway, let’s check out a previous commit.
Right-click the first commit in our timeline and select “Checkout Commit”:
Sublime Merge will likely display a warning message about a “detached head”, and the timeline view will change to look something like this:
There is a lot going on here! Some things worth noticing:
The
HEAD
label on the “Initial Commit” entry. This label refers to the point in the timeline we currently are “visiting”. Usually,HEAD
points to the most recent commit and is hidden from the timeline view. Because we’ve moved back in time, the label now appears to indicate this.There is a dotted line running from “Initial commit” to the top of the list, in parallel with all the other commits we made. This is a visual indicator that if we make any changes to our files now, they represent a completely different timeline than the one we made our previous commits on.
There is no name for this brave new timeline, and hence HEAD is “detached”. Any changes and commits we make will get lost the next time we return to the main timeline, since we have no name to refer to them with. There are proper ways to make changes on an alternate timeline, but we won’t discuss them in this workflow.
As a rule, we don’t check out a previous commit to make changes. We check it out to view the previous state of our work. We’ll talk about how to “undo” things in a bit.
All that discussion aside, open your journal folder and take a look:
The readme.txt
file reflects its contents from the beginning of our tutorial, and the recipe.txt
file is completely missing! This is because, at the time of the checked-out commit, it didn’t exist yet. Luckily it’s not lost forever, though: it’s stored safely in our repository’s history (in this case, in commits that “will happen” in the “future”, according to the main timeline).
Let’s return to the present. In Sublime Merge, take a look at the left side of the window. The Branches
list records all of the named timelines in our repository. Right-click Main
and select Checkout main
:
The timeline view should return to normal:
We’ve returned to the present. Take a look at your folder window, everything there should be back to normal too 😄.
Undoing something from history [🔗]
Let’s say we made a mistaken change to our text in the past, and want to undo those changes. Git generally doesn’t want us to alter the historical timeline. Instead, it’ll have us make a new commit that “undoes” the changes in the past we wish to remove. This is called a revert.
Let’s say we want to undo the contents of the second commit we made. That is, the commit that changed our favorite animal name to its taxonomic classification and listed our favorite song. We want to keep our recipe around though – we’re just tired of scientific names we don’t understand and old songs we don’t want to hear anymore.
Right-click that second commit and choose “Revert”:
Uh oh! You’ll see a message about a failure, and some new stuff will appear in the summary tab:
What happened was called a conflict: Git couldn’t figure out how to make the changes we requested (fixing the animal line) without also screwing up some of the changes that happened later on (adding the recipe line). This is a common error to encounter, and very worth our while to get experience dealing with!
Whenever we encounter a conflict, we need to open the file in a text editor and fix the conflicted portions of it. Those portions are labelled with a specific notation:
Wherever these angle brackets <<<<<<< ... >>>>>>>
appear, they indicate two different versions of the same section of text, separated by the =======
. Git couldn’t choose between them, so it wants us to replace this conflicting section, including the angle brackets <<<<<<< ... >>>>>>>
, with the version we want. Maybe this is the top version. Maybe it’s the bottom. Maybe it’s some clever combination of the two.
For the rever we’re working on, we want to keep the Favorite Animal
line from the bottom version, and the Favorite Recipe
line from the top version. So let’s open readme.txt
in our text editor and replace the <<<<<<< ... >>>>>>>
brackets and everything between them with the lines we want to keep:
Save the file and return to Sublime Merge. Click the “Stage” button on readme.txt
to include our changes in the upcoming revert:
Finally, click the “Complete” button:
Our timeline will now include a new commit which “undoes” those changes we wanted to erase:
Hooray!
â›” Git “resets”â›”
You might have noticed another option when right-clicking to reset main to a given commit. This edits the timeline so that it stops at the commit we are resetting to, and any commits that happened afterwards get deleted. This means we’re actually erasing history, which is a very dangerous thing to do! In rare occasions it’s the right choice, but you should always ask someone with more Git experience before actually doing it.
What next? [🔗]
Your repository doesn’t have to just live on your computer – it’s possible to back it up to the cloud (or another computer, or multiple locations on your current computer) and keep the timelines consistent across all of them. We’ll cover that in the next chapter.