Version Control with Git

Version Control

What Is Version Control?

Version control lets us manage software development safely:

  • Track changes

  • Look at older revisions

  • Revert to earlier revisions

  • Share code/collaborate easily

  • Easily go back to a previously working version if you break something

You may have used “homemade version control” like this:

  • resume-version-1.docx

  • resume-version-2.docx

  • resume-version-2FINAL.docx

  • resume-version-2NEWFINAL.docx

  • resume-version-2UPDATENEWFINAL.docx

Git is like this — but a million times better

Multiple Files

Tracks entire project (could be many files in folders, even):

$ ls
NOTES          app_setup.py      db_reset.py         search.py
README         config.py         flask/              tests.db
app/           db_create.py      requirements.txt    tests.py

Git Intro

Git

  • Most popular Open Source version control program

  • Runs on Linux, OSX, and Windows

  • Main concern: safety!

Terminology

Directory

Folder of files (which can contain subdirectories).

Repository

Project kept under version control; can contain subdirectories.

Working Copy

Your particular copy of a repository.

Until we turn a directory into a repository, git won’t work
(and isn’t tracking anything):

$ mkdir play
$ cd play

$ git status
fatal: Not a git repository (or any of the parent directories): .git

Configuring Git

  • Git wants to know who you are so it can identify the commits by user

  • Two commands (one for email, one for name):

$ git config --global user.email "balloonicorn@hackbrightacademy.com"
$ git config --global user.name "Balloonicorn Jones"
  • Do this as soon as possible so your code is attributed to you correctly

  • You only need to do this one time

Creating Repository

Turn your directory into a repository with git init.

$ git init
Initialized empty Git repository in /home/user/src/play/.git/

You only need to do this once.

You can do it when you create the project or at a later point.

What does git init do?

git init will create a directory called .git/ wherever you run the command. So, a Git repository is really just any directory that contains a valid .git/ folder. As long as your project already has a .git/ directory, you’ll never need to run git init again.

Untracked Files

Let’s create a file, hello.py, in our repository

print('Hello')

Git can tell we’ve created this file and that it’s untracked

$ git status
On branch main

Initial commit

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

        hello.py

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

Tracking a File

For Git to manage files, “track” them with git add:

$ git add hello.py

Once we do that, we can see that Git is tracking our file:

$ git status
On branch main

Initial commit

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

        new file:   hello.py

First Check-In!

Our program is working! Let’s “commit” it:

$ git commit -a -m "Say hello"
[main (root-commit) 6f267125] Say hello
 1 file changed, 1 insertion(+)
 create mode 100644 hello.py
-a

Commit all tracked files

-m

Add a commit message

Why -a?

Instead of using -a, you can specify individual files/directories to commit, like git commit -m "Message" file1.py file2.py — but this is less common, since you’ll typically want to check in the entire repository at a time. Do note, however, that this will commit all files that have been changed or deleted (new files you have not told git about are not affected).

If you leave off the -m, Git will open up an editor for you to enter a commit message there. We went ahead and configured Git so it uses VS Code as its text editor.

By default, Git will use Vim as its text editor. Vim is a powerful (if difficult to learn how to use at first) editor that comes with macOS and Linux operating systems. Don’t be taken aback when Git uses Vim as its default text editor! This may happen on your personal laptop or other machines you use in the future. If it opens up Vim and you don’t know how to use it, type :q then press Return to quit. You can then re-type your commit command with the -m switch.

Did it Work?

git status shows us the state of our repository:

$ git status
On branch main
nothing to commit, working directory clean

git log shows us a log of our revision history:

$ git log
commit faa215bd9dd82ce8dca58f3ab3d0ece49d6fb351
Author: Jessica Developer <jess@gmail.com>
Date:   Wed Sep 17 21:13:02 2021 -0700

  Say hello

A Note on Commit Messages

_images/git_commit.png
  • Keep messages professional and informative

  • Potential employers can see your Git commit messages!

Keep Working

Make a change to hello.py:

print('Hello')
print('World')

Git knows we’ve modified the file since we committed it:

$ git status
On branch main
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:   hello.py

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

Let’s check in our changed version:

$ git commit -a -m "Add world"
[main 411455e8] Add world
 1 file changed, 1 insertion(+)

And So On

Keep editing and committing every so often.

Logs

Git Log

git log shows us all history, from most recent to oldest:

$ git log
commit d9808883c4432ee61c56a1df7d0c5330a5a2df7c
Author: Jessica Developer <jess@gmail.com>
Date:   Wed Sep 17 21:17:18 2021 -0700

    Add world

commit faa215bd9dd82ce8dca58f3ab3d0ece49d6fb351
Author: Jessica Developer <jess@gmail.com>
Date:   Wed Sep 17 21:13:02 2021 -0700

    Say hello

As your needs get more sophisticated, git log has many options, such as only showing recent history, work by one person, work on a single file or directory of your project, etc.

Reviewing & Reverting

ARGH!

We’ve changed hello.py

print('Hello')
print('World')
Yuck

And now we’ve broken our code:

$ python3 hello.py
Hello
World
Traceback (most recent call last):
  File "hello.py", line 3, in <module>
    Yuck
NameError: name 'Yuck' is not defined

What Changed?

git diff can tell us what’s different:

$ git diff
diff --git a/hello.py b/hello.py
index 3808fc1..8ef9f2d 100644
--- a/hello.py
+++ b/hello.py
@@ -1,2 +1,3 @@
 print("Hello")
 print("World")
+Yuck

New lines in +green, deleted lines in -red.

Just Take Me Back

To return to our last revision, use git reset --hard:

--hard option means do this, even if we lose our changes, so be careful!

$ git reset --hard
HEAD is now at 411455e8 Add world.

Advanced resetting

You can even go back to earlier versions with git reset by specifying an earlier revision ID or tag — but be warned, you’re losing history this way! This is useful only if you’re certain you never want the changes you made after a certain revision.

To revert to an earlier revision:

$ git reset --hard finished_exercise

You can either provide a tag name or a revision ID to return to. Be careful.

Recap

What Did We Learn?

  • Git tracks files in “repository”

  • Must initialize with git init once

  • Add files you want to track with git add

  • When things work or you’ve done a lot of work, commit

    • Don’t be a jerk to your future self!

  • git status shows status of working directory

  • git log shows what you’ve committed

  • git diff shows changes since you committed

  • You can compare to/revert back to last revision

Further Study & Resources

Coming Up

  • GitHub (using git in the cloud)

Git Cheatsheet

You can try this out, from top to bottom, with these commands:

Make a directory and go into it

$ cd ~/src
$ mkdir play
$ cd play

Turn into a git repository

$ git init

Add a file with one line

$ echo 'print("Hello")' > hello.py

See that git knows it’s untracked

$ git status

Tell git to track it

$ git add hello.py

Commit our change and see that it’s committed

$ git commit -a -m "Say hello" `:cmd:
$ `git status
$ git log

Add a second line to it

$ echo 'print("World")' > hello.py

See that git knows it changed

$ git status

Commit change and see that git tracked that

$ git commit -a -m "Add world"
$ git log

Add a third, bad line to our program; see that it breaks things

$ echo 'Yuck' >> hello.py
$ python3 hello.py

What changed?

$ git diff

Add the “–hard” option to say it’s ok to lose our “Yuck” line

$ git reset --hard