Whether you code or write documents, often you end up with multiple versions of the same file. You may want to archive one set of changes that are not needed at the moment, then send another set of changes to your colleagues for a review. At a certain point, keeping track of all these versions becomes unfeasible.
Tools like Dropbox or Google Drive, which you may know already, can help a bit. These tools allow you to share your files easily, or to restore their content to an earlier point in time. Here's an example:
Unfortunatelly, you can only see different versions of a single file. Also, it's hard to tell which version you might want to restore since there is no indication of how individual versions differ. A relatively large project wouldn't be manageable with this approach.
Therefore, programmers tend to use more powerful tools dubbed version control system (VCS). Currently, the most popular one is Git, and we'll learn more about it in this lesson.
We will rely on the command line. If you are not confident working with it yet, look at the introduction.
Remember: don't write the $
at the start.
It is shown here to indicate the beginning of each command.
The process of installing Git is described here. If you have skipped the lesson before, you might want to get back to it now.
Each project that you want to version-control needs to be stored in its own directory.
Create a new directory now and navigate inside (use the command cd
).
Then, create a new Git repository using the command git init
:
$ git init
Initialized empty Git repository in ./.git/
At first glance, it looks like nothing happened.
This command created a hidden directory with the name .git
and stored some information in there.
You can see the file using ls -a
(Linux) or dir /a
(Windows).
.git
is a hidden directory because it is managed only by Git
and you shouldn't be changing anything inside.
The repository is empty for now.
You can see for yourself by invoking git status
, a command that shows information
about the state of the repository:
$ git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)
“On branch master” refers to so-called branches, we'll get back to that later. “Initial commit” means that there is no revision stored yet. And “nothing to commit” says that there are no files to be saved and versioned in the directory.
Try adding something to Git now!
Create a new file poem.txt
and write a short poem inside.
It should span at least five lines so that we have enough to work with.
Then, try executing git status
again: Git reports that there is a new
file in the directory and that it isn't managed by Git yet.
$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
poem.txt
nothing added to commit but untracked files present (use "git add" to track)
We need to make Git track each new file explicitely. Let's do that for the file with your poem:
$ git add poem.txt
Then check the state of the repository again:
$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: poem.txt
The lines in green (“changes to be committed”) will be included in the next batch of changes (a commit) that you will create. Let's create our first commit:
$ git commit
[master (root-commit) 1a009f4] First revision
1 file changed, 6 insertions(+)
create mode 100644 poem.txt
After entering this command, an editor opens where you can write a short description
of this commit, briefly summarizing what changes have been made.
This is referred to as a commit message. For now, a simple First revision
will do.
You can ignore the existing lines starting with #
, these are just for your information.
Git will ignore them as well. Finally, save the file and close the editor.
Working with editors
In Windows, if you have set up your Git correctly, Notepad will be used as the editor; simply write something, save (Ctrl+S) and close (Alt+F4).
In Linux or macOS, an editor called Nano appears directly in the command line window. You can recognize it by the keyboard shortcut help on the bottom two lines. Write something, save using Ctrl+O, confirm the name of the file (Enter) and exit the editor using Ctrl+X.
If you haven't set up Git accordingly, Vim is invoked directly in the command line window
and will be used as the default editor.
It is a relatively complicated editor and learning to use it is beyond the scope
of this lesson. You can recognize it by one or two lines at the bottom that show a path
to a temporary file that you are currently editing.
In that case, first press
Esc, then type :q!
(colon, lower letter Q, exclamation mark)
and confirm by pressing Enter.
Then set up Git corrently and try git commit
again.
Try reporting on the repository again:
$ git status
On branch master
nothing to commit, working tree clean
This short report means that nothing has changed since the last commit. That is expected since we've just commited all our changes!
Now let's have a look at what has changed in the last commit.
Execute git show
:
$ git show
commit 1a009f4267d5a6ab7ece87cb7514f5b803692e39
Author: Adéla Novotná <adela.novotna@example.cz>
Date: Mon Mar 20 14:51:34 2017 +0100
First revision
diff --git a/poem.txt b/poem.txt
new file mode 100644
index 0000000..558d133
--- /dev/null
+++ b/poem.txt
@@ -0,0 +1,6 @@
+Holka modrooká, nesedávej u potoka
+Holka modrooká, nesedávej tam
+
+V potoce je hastrmánek
+Zatahá tě za copánek
+Holka modrooká, nesedávej tam
Notice the unique Git commit ID that allows you to return to this state of your project at any point in the future. The author's name, the date of this commit's creation and the commit message are also listed, along with the summary of changes: a new file poem.txt containing the text in green has been added.
When the output of a command is too long, you can browse it using the keys (↓, ↑, PgUp, PgDn). In such case, exit the browsing mode by pressing q for Quit.
Text encoding in Windows
If you have trouble with displaying special characters like letters with diacritics,
enter the following command before git show
:
> set LC_ALL=C.UTF-8
This command will only configure the current command line window. It will have to be entered for any new window that you open.
Make a small change in your poem; replace one word, change punctuation, or add a new verse. Then check the status of the Git repository again.
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: poem.txt
no changes added to commit (use "git add" and/or "git commit -a")
The file is shown in red again. Something has changed inside!
To see the details, execute the command git diff
.
$ git diff
diff --git a/poem.txt b/poem.txt
index 558d133..24e2384 100644
--- a/poem.txt
+++ b/poem.txt
@@ -1,6 +1,9 @@
-Holka modrooká, nesedávej u potoka
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej u potoka
+Holka modrooká
+Nesedávej tam
V potoce je hastrmánek
Zatahá tě za copánek
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej tam
The changes are shown on a per-line basis. The lines in red beginning with - indicate the original lines that have been removed; the lines in green starting with + show the newly added lines.
Even if just a single word or a letter has changed on any given line, the whole line will be listed as removed and added (including the small change). This interpretation can be customized if needed, but it's a good idea to get used to the default behavior.
It is easy to see what exactly has changed since the last commit.
If your program stops working, but the last commited version still worked,
use git diff
–
one of the changes listed must have introduced the error!
The line beginning with @@ indicates the location in the file where the changes occur. In the example above, the excerpt of the original file starts at line number 1 and it is 6 lines long; the matching block in the changed varsion starts at line 1 as well, but it is 9 lines long.
If you are satisfied with the changes, stage them for the next commit:
$ git add poem.txt
As usual, check the status
of the repository; the file in green will be included
within the next commit.
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: poem.txt
Before we finalize the next commit, let's talk about the best practices
in formulating the commit messages.
There are common conventions that most programmers follow:
the first line summarizes the changes, the second line is left blank,
and the following lines list the reasons for the change or describe
the changes themselves in more detail.
Each line should have under 70 characters in length;
the lenth of the comments (lines starting with #
) can serve as a guide here.
It is not worth going into detail for changes that are trivial or obvious;
rather, focus on the broader context and reasons for the changes.
Anything that can help whomever will try to understand the changes in the commit;
this might include you few months later.
My commit message will be the following:
Split long lines
Typically, each verse of a poem goes on its own line. I think
that it's easier to read like this. (Although, the real reason was
to demonstrate git diff.)
If you ever have trouble summarizing your changes using just 70 characters, you might be taking too many steps at once. E.g. "change string X and add loop Y" might be better to commit as two separate revisions.
Finally, use git commit
to create your second revision,
and then check it using git show
:
$ git show
commit 81cbabb3bd3cd2f3896dd41b20012c44dbd69031
Author: Adéla Novotná <adela.novotna@example.cz>
Date: Mon Mar 20 14:51:34 2017 +0100
Split long lines
Typically, each verse of a poem goes on its own line. I think
that it's easier to read like this. (Although, the real reason was
to demonstrate git diff.)
diff --git a/poem.txt b/poem.txt
index 558d133..24e2384 100644
--- a/poem.txt
+++ b/poem.txt
@@ -1,6 +1,9 @@
-Holka modrooká, nesedávej u potoka
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej u potoka
+Holka modrooká
+Nesedávej tam
V potoce je hastrmánek
Zatahá tě za copánek
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej tam
The diagram below visualizes what each command demonstrated thus far does exactly, and how the changes move from “not staged” to “commited”.
Now that we have created our first few revisions in the repository,
let's demonstrate more commands that will help us understand
the whole history of our Git repository.
The first command is git log
.
$ git log
commit 81cbabb3bd3cd2f3896dd41b20012c44dbd69031
Author: Adéla Novotná <adela.novotna@example.cz>
Date: Mon Mar 20 14:51:34 2017 +0100
Split long lines
Typically, each verse of a poem goes on its own line. I think
that it's easier to read like this. (Although, the real reason was
to demonstrate git diff.)
commit 1a009f4267d5a6ab7ece87cb7514f5b803692e39
Author: Adéla Novotná <adela.novotna@example.cz>
Date: Mon Mar 20 14:51:34 2017 +0100
First revision
git log
prints all commits starting from the newest one and going
all the way back to the initial commit at the origin of the repository.
When there are so many commits that they don't fit on a single screen of your command line window, you can browse back and forth using PgUp/PgDn. Finally, exit by pressing q.
There are many options that customize the output of git log
.
They are all described (at great length)
in the built-in documentation (command git help log
).
If the help is displayed in the command line window, press q
to exit.
My personal favorite combination is git log --oneline --graph --decorate --cherry-mark --boundary
.
To see all details about any commit,
execute git show 5ff0b
, replacing 5ff0b
with the first few characters of the Git commit ID.
The command line can convey all sorts of information,
but not always in a clear way.
A graphical application called gitk offers a more intuitive look
at the history of your repository;
you can start it using the command gitk --all
:
$ gitk --all
The application doesn't look very appealing (almost as if
it has been designed by programmers who emphasise substance over form),
but it will suit our needs.
Get familiar with it first, then close it, commit a few more sets of changes
and finally explore them using git log
and gitk --all
.
These are the Git basics that we'll need in the following lessons.
Whenever you perform git add file
and git commit
,
the current version of the file is saved and will be accessible even if you delete the file later.
You can always view any past version of any file in your repository,
and review all changes made since the last time the project was saved.
Maybe all this sounded unnecessarily too complicated for a beginner. Indeed, our projects will be relatively simple and easy to manage even without the use of Git. But it's a good idea to learn using it from the very beginning; when you get to participate in bigger projects, already being used to Git will come very handy.
So, from now on, whenever you make even a small but meaningful change to your program,
as long as the program works at least as well as it did before,
use git add
and git commit
to save the change in Git.