Introduction to Git Tutorial

Let's check our current directory.

In [1]:
pwd
/Users/knuths/Documents/Tutorials/Git/notebook/temporary_git

Let's check the status of our repository.

In [2]:
git status
fatal: Not a git repository (or any of the parent directories): .git

Whoops! We have not made this a repository yet. Let's fix that and track an existing project.

In [3]:
git init
Initialized empty Git repository in /Users/knuths/Documents/Tutorials/Git/notebook/temporary_git/.git/

In [4]:
git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	Git Tutorial.ipynb

nothing added to commit but untracked files present (use "git add" to track)

Now we see that we are tracking our project. We are on the master branch, we have untracked flies (this notebook), and haven't committed anything.

We do see a new directory in the parent directory however.

In [5]:
ls -laF
total 56
drwxr-xr-x   4 knuths  AD\Domain Users    136 May  1 10:08 ./
drwxr-xr-x   3 knuths  AD\Domain Users    102 May  1 10:06 ../
drwxr-xr-x  10 knuths  AD\Domain Users    340 May  1 10:08 .git/
-rw-r--r--@  1 knuths  AD\Domain Users  26344 May  1 10:06 Git Tutorial.ipynb

The .git directory contains all the important information about our project.

Now let's create a text file and check the status of our project once we add the file.

In [6]:
touch temporary_git_file.txt
git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	Git Tutorial.ipynb
	temporary_git_file.txt

nothing added to commit but untracked files present (use "git add" to track)

Here we see that we have an untracked file (in addition to the notebook), temporary_git_file.txt. We also see that we are still on the master branch.

Before we go any further, we are going to set up our project so that we are ignoring the notebook file. I don't want to track it for the purposes of this tutorial because it will be confusing when what we are really interested in doing is tracking the changes in the temporary_git_file. To do this, we add a file called .gitignore to the root directory of our project, and then add the name of the file we want to ignore.

In [7]:
pwd
/Users/knuths/Documents/Tutorials/Git/notebook/temporary_git

In [8]:
touch .gitignore
In [9]:
ls -laF
total 48
drwxr-xr-x   6 knuths  AD\Domain Users    204 May  1 10:10 ./
drwxr-xr-x   3 knuths  AD\Domain Users    102 May  1 10:06 ../
drwxr-xr-x  10 knuths  AD\Domain Users    340 May  1 10:08 .git/
-rw-r--r--   1 knuths  AD\Domain Users      0 May  1 10:10 .gitignore
-rw-r--r--@  1 knuths  AD\Domain Users  23977 May  1 10:10 Git Tutorial.ipynb
-rw-r--r--   1 knuths  AD\Domain Users      0 May  1 10:08 temporary_git_file.txt

In [10]:
echo "Git Tutorial.ipynb" > .gitignore
cat .gitignore
Git Tutorial.ipynb

In [11]:
git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	.gitignore
	temporary_git_file.txt

nothing added to commit but untracked files present (use "git add" to track)

Now we see that git no longer cares about our ipython notebook file. It only cares about the .gitignore file. Let's stage and commit that file and get it out of the way.

In [12]:
git add .gitignore
In [13]:
git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   .gitignore

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	temporary_git_file.txt


In [14]:
git commit -v -m 'gitignore'
[master (root-commit) bcb7d33] gitignore
 1 file changed, 1 insertion(+)
 create mode 100644 .gitignore

In [15]:
git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	temporary_git_file.txt

nothing added to commit but untracked files present (use "git add" to track)

So, we have committed the .gitignore file, but we are still not tracking our temporary_git_file.txt. Let's change that.

In [16]:
git add temporary_git_file.txt
In [17]:
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   temporary_git_file.txt


Now we see that we are tracking the temporary_git_file.txt. It's currently "staged" but not yet "committed". We know it's staged since it says "Changes to be committed".

Let's change the temporary_git_file.txt and run the status command again.

In [18]:
echo "Change 1" > temporary_git_file.txt
cat temporary_git_file.txt
Change 1

In [19]:
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   temporary_git_file.txt

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:   temporary_git_file.txt


Now we see that our file appears under the "Changes to be committed" and "Changes not staged for commit" heading. How are we both staged and unstaged?

This is because we created our file, staged it, and then made a change that has not yet been staged. If we committed right now, the "Change 1" alteration to the temporary_git_file.txt wouldn't be included.

So let's quick get that change staged and check our status again.

In [20]:
git add temporary_git_file.txt
In [21]:
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   temporary_git_file.txt


Looking at the output of the git status command, we don't really get much information about the exact contents of the file or what was changed.

Before we commit, let's make another change and use a more versed way of getting at exactly what was changed.

In [22]:
echo "Change 2" >> temporary_git_file.txt
cat temporary_git_file.txt
Change 1
Change 2

In [23]:
git diff --cached
diff --git a/temporary_git_file.txt b/temporary_git_file.txt
new file mode 100644
index 0000000..bf58b17
--- /dev/null
+++ b/temporary_git_file.txt
@@ -0,0 +1 @@
+Change 1

This is a lot more verbose. But wait, where's "Change 2" that we added? Ah, git diff will only tell us about changes that have been staged. If we staged our last change and run get diff again we should see our "Change 2" addition.

In [24]:
git add temporary_git_file.txt
In [25]:
git diff --cached
diff --git a/temporary_git_file.txt b/temporary_git_file.txt
new file mode 100644
index 0000000..10a7b9e
--- /dev/null
+++ b/temporary_git_file.txt
@@ -0,0 +1,2 @@
+Change 1
+Change 2

Yay! Ok, let's commit. Remember, anything unstaged will not be committed. They stay though as modified files on your desk. We have staged everything so this won't be a problem for us here.

In [26]:
git commit -v -m 'initial version'
[master 91ae179] initial version
 1 file changed, 2 insertions(+)
 create mode 100644 temporary_git_file.txt

Here's we've committed our changes to a local repository. We have added metadata to this change that says this is the initial version. We did this with the "-m" flag, but if you don't add that a text editor will open and allow you to add it in on the spot. The "-v" adds in the "git diff" output so your metadata is a bit more verbose.

At any time, if I want to look at my commit history, I can see that here.

In [27]:
git log
commit 91ae1791efb66698a249dd8fa7ff2ef57e7446b6
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:16:49 2014 -0600

    initial version

commit bcb7d33edf73666481633100645ad44e8074af65
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:10:46 2014 -0600

    gitignore

Here we see the two commits we've already made, who made them, when they were made, and the commit id.

Let's do some file recovery.

Let's see what happens when we change our text file, and remove it without staging or committing the revisions.

In [28]:
echo "Change 3" >> temporary_git_file.txt
cat temporary_git_file.txt
Change 1
Change 2
Change 3

In [29]:
rm temporary_git_file.txt
In [30]:
ls
Git Tutorial.ipynb

The file is gone. Let's check the status.

In [31]:
git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    temporary_git_file.txt

no changes added to commit (use "git add" and/or "git commit -a")

The file isn't really gone though. It can be recovered. What is gone though is "Change 3", since as far as git is concerned, you never made that change.

The good news is that we can recover the file with the changes from our last commit ("Change 2" in this case).

In [32]:
git checkout temporary_git_file.txt
In [33]:
cat temporary_git_file.txt
Change 1
Change 2

As we suspected, we lost our last change ("Change 3"), but at least we have everything else.

Now let's try another recovery. Let's make some changes to the file and remove it, but first we'll stage the changes.

In [34]:
echo "Change 3a" >> temporary_git_file.txt
cat temporary_git_file.txt
Change 1
Change 2
Change 3a

In [35]:
git add temporary_git_file.txt
In [36]:
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   temporary_git_file.txt


In [37]:
rm temporary_git_file.txt
In [38]:
ls
Git Tutorial.ipynb

Oh no! The file is gone again! Let's run our git status.

In [39]:
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   temporary_git_file.txt

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

	deleted:    temporary_git_file.txt


But! We're in luck. Our staged changes show that we have modified our most recent file, and the unstaged changes show that we deleted the file. So really, all we need to do here is commit the changes and checkout our file, and all is good.

In [40]:
git commit -v -m 'Version 2'
[master 21f72a2] Version 2
 1 file changed, 1 insertion(+)

In [41]:
ls
Git Tutorial.ipynb

The file is still gone, but if we check it out from our local repository then we can get our latest change.

In [42]:
git checkout temporary_git_file.txt
In [43]:
ls
Git Tutorial.ipynb
temporary_git_file.txt

In [44]:
cat temporary_git_file.txt
Change 1
Change 2
Change 3a

Yippee!! The world is good.

Other Fun Items

Again, at any time, if I want to look at my commit history, I can see that here.

In [45]:
git log
commit 21f72a23430bbdc754e13d7824824951a6490072
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:24:28 2014 -0600

    Version 2

commit 91ae1791efb66698a249dd8fa7ff2ef57e7446b6
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:16:49 2014 -0600

    initial version

commit bcb7d33edf73666481633100645ad44e8074af65
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:10:46 2014 -0600

    gitignore

Yuck! I don't like what I called my last commit. Let's go back and change that.

In [46]:
git commit --amend -m 'Second Version'
[master b219420] Second Version
 1 file changed, 1 insertion(+)

In [47]:
git log
commit b2194202a25d396bb2b23fbfdfc411e5661070cd
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:24:28 2014 -0600

    Second Version

commit 91ae1791efb66698a249dd8fa7ff2ef57e7446b6
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:16:49 2014 -0600

    initial version

commit bcb7d33edf73666481633100645ad44e8074af65
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:10:46 2014 -0600

    gitignore

You can change the metadata or even add files to the previous commit that you forgot you wanted to add.

In [48]:
touch temporary_git_file1.txt
echo "Change 1 New Commit" >> temporary_git_file1.txt
cat temporary_git_file1.txt
Change 1 New Commit

In [49]:
git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	temporary_git_file1.txt

nothing added to commit but untracked files present (use "git add" to track)

In [50]:
git add temporary_git_file1.txt
git commit --amend --no-edit
[master 70753b2] Second Version
 2 files changed, 2 insertions(+)
 create mode 100644 temporary_git_file1.txt

In [51]:
git log
commit 70753b252d59a8403062600d1252d9e018b2029b
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:24:28 2014 -0600

    Second Version

commit 91ae1791efb66698a249dd8fa7ff2ef57e7446b6
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:16:49 2014 -0600

    initial version

commit bcb7d33edf73666481633100645ad44e8074af65
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:10:46 2014 -0600

    gitignore

This doesn't tell me much about what files were changed in each commit though. I can do that a couple of ways.

In [52]:
git show
commit 70753b252d59a8403062600d1252d9e018b2029b
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:24:28 2014 -0600

    Second Version

diff --git a/temporary_git_file.txt b/temporary_git_file.txt
index 10a7b9e..6b01bff 100644
--- a/temporary_git_file.txt
+++ b/temporary_git_file.txt
@@ -1,2 +1,3 @@
 Change 1
 Change 2
+Change 3a
diff --git a/temporary_git_file1.txt b/temporary_git_file1.txt
new file mode 100644
index 0000000..ddaf82d
--- /dev/null
+++ b/temporary_git_file1.txt
@@ -0,0 +1 @@
+Change 1 New Commit

This shows me every file that was changed in the last commit and what was changed. If your files are really long though this can get cumbersome. If you just want to know what files were changed, you can do the following:

In [53]:
git diff-tree --no-commit-id --name-only -r 70753b252
temporary_git_file.txt
temporary_git_file1.txt

Where the number at the end is part of the commit id number. I believe you need at least seven numbers from the id.

Let's say I want to get rid of the last commit entirely. I can do that with:

In [54]:
git reset HEAD^
Unstaged changes after reset:
M	temporary_git_file.txt

In [55]:
git log
commit 91ae1791efb66698a249dd8fa7ff2ef57e7446b6
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:16:49 2014 -0600

    initial version

commit bcb7d33edf73666481633100645ad44e8074af65
Author: Shelley Knuth <shelley.knuth@colorado.edu>
Date:   Thu May 1 10:10:46 2014 -0600

    gitignore

Or find someone that made the EGREGIOUS error last week.

In [56]:
git blame temporary_git_file.txt
91ae1791 (Shelley Knuth     2014-05-01 10:16:49 -0600 1) Change 1
91ae1791 (Shelley Knuth     2014-05-01 10:16:49 -0600 2) Change 2
00000000 (Not Committed Yet 2014-05-01 10:36:55 -0600 3) Change 3a

That darn Shelley.

Finally, some branch commands. There's a lot you can do here, but these are the basic commands to get you going.

To check which branch you are on.

In [57]:
git branch
* master

To create a new branch

In [58]:
git checkout -b new_branch
M	temporary_git_file.txt

Switched to a new branch 'new_branch'

In [59]:
git branch
  master
* new_branch

To change branches.

In [60]:
git checkout master
M	temporary_git_file.txt

Switched to branch 'master'

And finally, to merge branches.

In [61]:
git merge new_branch
Already up-to-date.

In [62]:
git branch
* master
  new_branch