Version control enables us to make incremental changes to our code base. We can then restore previously working versions, compare changes, and recover details about why a change was made.
Git should already be installed if you set up your development environment using this project's Vagrantfile, but in case it's not, run the following in your Ubuntu terminal:
sudo apt-get install git
...
$ git --version
git version 2.0.4
git init
creates a new repositorygit status
lists files that have changedgit add
"stages" files to commitgit commit
commits staged changes to a repositorygit log
lists all commitsgit show
shows changes in a commitgit diff
shows what's changedgit reset
"unstages" changesgit revert
reverts a commitgit branch
encapsulates changesgit merge
merges one branch into anothergit pull
pulls commits from a remote repositorygit push
pushes commits to a remote repositorygit clone
makes a local copy of a remote repository
-
Create a new directory:
$ mkdir foo
-
Change into that directory:
$ cd foo
-
Create a new git repository:
$ git init
$ git status
On branch master
Initial commit
nothing to commit
-
Create a file:
$ echo "hi" > file.txt
-
Observe the file is not yet "tracked" by the git repository:
$ git status ... Untracked files: (use "git add <file>..." to include in what will be committed) file.txt
-
Add the file to the list of changes "staged" for the next commit:
$ git add file.txt
-
Observe the file is now in the list of changes for the next commit:
$ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file.txt ...
-
Finalize the commit.
$ git commit
Git will launch your default text editor. Write a brief message, eg "Add file", and exit the text editor.
If you haven't already configured git with your email and name, you'll be prompted to do so:
$ git commit *** Please tell me who you are. Run git config --global user.email "[email protected]" git config --global user.name "Your Name"
$ git log
commit c9b26e67839d1e53b017b4a02c55bb8e7f4eefec
Author: Erik Eldridge <[email protected]>
Date: Fri Mar 13 04:22:00 2015 +0000
Add file
$ git show c9b26e67839d1e53b017b4a02c55bb8e7f4eefec
commit c9b26e67839d1e53b017b4a02c55bb8e7f4eefec
Author: Erik Eldridge <[email protected]>
Date: Fri Mar 13 04:22:00 2015 +0000
Add file
diff --git a/file.txt b/file.txt
new file mode 100644
index 0000000..45b983b
--- /dev/null
+++ b/file.txt
@@ -0,0 +1 @@
+hi
-
Create another change, eg:
$ echo "world" >> file.txt
-
Run
git diff
to see what has changed:$ git diff diff --git a/file.txt b/file.txt index 45b983b..3b097cd 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hi +world
-
Run
git add
to stage the change made above -
Run
git status
to see what's staged for the next commit -
Run
git reset
to unstage:$ git reset Unstaged changes after reset: M file.txt
-
Add and commit (using the -m shortcut) the change:
$ git add file.txt $ git commit -m "Update file.txt" [master 59d700c] Update file.txt 1 file changed, 1 insertion(+) $ git log commit 06abe628a703ed148bfcf21c45efdd2283609d40 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:27:42 2015 +0000 Update file.txt commit c9b26e67839d1e53b017b4a02c55bb8e7f4eefec Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:22:00 2015 +0000 Add file ...
-
Run
git revert
to undo the given change:$ git revert 06abe628a703ed148bfcf21c45efdd2283609d40 [master f7d0faa] Revert "Update file.txt" 1 file changed, 1 deletion(-)
-
Run
git log
to see the reversion:$ git log commit f7d0faa478b7b2ee19feba9c0d76bebfab37b061 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:32:07 2015 +0000 Revert "Update file.txt" This reverts commit 06abe628a703ed148bfcf21c45efdd2283609d40. commit 06abe628a703ed148bfcf21c45efdd2283609d40 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:27:42 2015 +0000 Update file.txt commit c9b26e67839d1e53b017b4a02c55bb8e7f4eefec Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:22:00 2015 +0000 Add file
To ensure a repository always contains functional code, we can create a "branch" to encapsulate our work in progress.
By convention, the main branch of a repository is usually called "master".
-
Run
git branch
to see your branches:$ git branch * master
-
Run
git branch
with a branch name to create a new branch:$ git branch foo
-
Run
git checkout
with a branch name to work in that branch:$ git checkout foo Switched to branch 'foo'
-
Make a change and commit, eg:
$ echo "a new change" >> file.txt $ git add file.txt $ git commit -m "Add a new change"
-
Use
git diff
to compare master and your current branch:$ git diff master diff --git a/file.txt b/file.txt index 45b983b..0a978b3 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hi +a new change
-
Use
git log
to see commits on your current branch that aren't on master:$ git log master..foo commit 9c249cd4035b675df73e92861afb0c1609d2a74b Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:40:05 2015 +0000 Add a new change
Merge changes from one branch into another using git merge
.
-
Checkout the branch you'd like to merge changes into, eg master:
$ git checkout master
-
Use
git merge
to merge changes from another branch:$ git merge foo Updating f7d0faa..9c249cd Fast-forward file.txt | 1 + 1 file changed, 1 insertion(+)
-
Compare the branches and observe there are no differences:
$ git diff master..foo
If Git can't merge branches cleanly, it will indicate conflicting lines and ask us to resolve.
-
Create a change on the master branch and commit, eg
$ echo "starting text" > file.txt $ git add file.txt $ git commit -m "Add starting text"
-
Create two new branches:
$ git branch bar $ git branch baz
-
Checkout each branch and make a different change to the same line of the same file:
$ git checkout bar Switched to branch 'bar' $ echo "bar text" > file.txt $ git add file.txt $ git commit -m "Add bar text" [bar 3557270] Add bar text 1 file changed, 1 insertion(+), 1 deletion(-) $ git checkout baz Switched to branch 'baz' $ echo "baz text" > file.txt $ git add file.txt $ git commit -m "Add baz text" [baz e76619d] Add baz text 1 file changed, 1 insertion(+), 1 deletion(-)
-
Checkout master and merge both branches into it:
$ git checkout master Switched to branch 'master' $ git merge bar Updating feac207..1f2e058 Updating 0c4320f..3557270 Fast-forward file.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git merge baz Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result.
-
View the conflicted state (using Unix's cat command):
$ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: (use "git add <file>..." to mark resolution) both modified: file.txt no changes added to commit (use "git add" and/or "git commit -a") $ cat file.txt <<<<<<< HEAD bar text ======= baz text >>>>>>> baz
-
Edit the file to remove all but the text you'd like to keep, eg:
$ vim file.txt $ cat file.txt baz text
-
Run
git add
andgit commit
to accept the resolved conflict -
View the changes in your log (using the -p flag to show the diffs):
$ git log -p commit 7c5d054732577aa89581e505e4468928a1a88e3b Merge: 3557270 e76619d Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:52:41 2015 +0000 Merge branch 'baz' Conflicts: file.txt commit e76619db788991b25c68a1290b37848bbc692d17 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:46:17 2015 +0000 Add baz text diff --git a/file.txt b/file.txt index d2bc3f2..a67f6b2 100644 --- a/file.txt +++ b/file.txt @@ -1 +1 @@ -starting text +baz text commit 355727053e3f85b758c7d3d82f9167e154067476 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:45:26 2015 +0000 Add bar text diff --git a/file.txt b/file.txt index d2bc3f2..132d0f8 100644 --- a/file.txt +++ b/file.txt @@ -1 +1 @@ -starting text +bar text commit 0c4320fa52e32c23bde122200737bf8b71769de5 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:43:02 2015 +0000 Add starting text diff --git a/file.txt b/file.txt index 0a978b3..d2bc3f2 100644 --- a/file.txt +++ b/file.txt @@ -1,2 +1 @@ -hi -a new change +starting text commit 9c249cd4035b675df73e92861afb0c1609d2a74b Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:40:05 2015 +0000 Add a new change diff --git a/file.txt b/file.txt index 45b983b..0a978b3 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hi +a new change commit f7d0faa478b7b2ee19feba9c0d76bebfab37b061 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:32:07 2015 +0000 Revert "Update file.txt" This reverts commit 06abe628a703ed148bfcf21c45efdd2283609d40. diff --git a/file.txt b/file.txt index 3b097cd..45b983b 100644 --- a/file.txt +++ b/file.txt @@ -1,2 +1 @@ hi -world commit 06abe628a703ed148bfcf21c45efdd2283609d40 Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:27:42 2015 +0000 Update file.txt diff --git a/file.txt b/file.txt index 45b983b..3b097cd 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hi +world commit c9b26e67839d1e53b017b4a02c55bb8e7f4eefec Author: Erik Eldridge <[email protected]> Date: Fri Mar 13 04:22:00 2015 +0000 Add file diff --git a/file.txt b/file.txt new file mode 100644 index 0000000..45b983b --- /dev/null +++ b/file.txt @@ -0,0 +1 @@ +hi
We now have experience working with a git repository on our local machine, but what happens if our laptop or virtual machine dies, or we want to coordinate with other developers? We can use a "remote" repository, ie a repository hosted on another machine, to avoid catastrophe and facilitate collaboration.
Github is widely used and provides an excellent interface for working with remote repositories.
Create an account if you don’t have one already. It's free for open source projects.
Github's set-up documentation describes how to configure your local environment so you can talk to github.
We'll use SSH to talk with Github, so follow Github's documentation for setting up SSH.
Setting this up can be a little tedious, so refer to Github's SSH support documentation if you run into trouble.
Setting up your Ubuntu vm will look like this:
$ ssh-keygen -t rsa -C "[email protected]"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/vagrant/.ssh/id_rsa.
Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub.
The key fingerprint is:
5a:d6:2f:b1:99:5e:c6:41:0f:e2:c1:69:81:61:8e:ca [email protected]
The key's randomart image is:
+--[ RSA 2048]----+
| oo. |
| +.. o |
| . . * o |
| . . + + o |
| E S + . . |
| + B . |
| . = = |
| . + |
| . |
+-----------------+
$ eval "$(ssh-agent -s)"
Agent pid 2244
$ ssh-add ~/.ssh/id_rsa
Identity added: /home/vagrant/.ssh/id_rsa (/home/vagrant/.ssh/id_rsa)
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAKEDM4noIPCkpjk39KrfSz0y4zFJVsiP7gv0Wazi1+uAP/np0WR82ylWK8TTBY6M6LrcYESkl4T4ssLOdDpUrH6jlvLhbBVYjjwPA+omVniAb2kgXGLFwIVIDTqHjNqNtoBzXEGgN5aU4/1sXvcsuEU5kxRq/1fM9XOxJvniLgcbQ5egD/aa6VYd9zqEekNeNqalg6ehXXiw6tSe3D/lFs2NxQn56tt0DQGZwrmXc36ziFEEM7rpcZX5iPFvDhr/6mp4fU93IXikSiWrVXkIzjVHQi23JkYX17nxIEWVzpRXZT/W9A8fQrZOBILKqyK+mtF+a4BrF0sPdUC8hxvxjHT [email protected]
Per the SSH instructions linked above, copy the id_rsa.pub contents you just printed into your Github account settings.
Follow Github's documentation for creating a repository. Look for "…or push an existing repository from the command line" on the page Github loads after you create a repository, and then tell your local repository where your remote respository is:
$ git remote add origin [email protected]:erikeldridge/cst-395-example.git
-
Use
git push
to push your changes to the remote repository you just created, eg:$ git push -u origin master Warning: Permanently added the RSA host key for IP address '192.30.252.131' to the list of known hosts. Counting objects: 20, done. Compressing objects: 100% (8/8), done. Writing objects: 100% (20/20), 1.48 KiB | 0 bytes/s, done. Total 20 (delta 3), reused 0 (delta 0) To [email protected]:erikeldridge/cst-395-example.git * [new branch] master -> master
-
Reload your repository's page on Github
-
Observe you can now see the file in your repository
-
Click the link to your "8 commits"
-
Observe Github provides a web interface to your git history
-
Browse around Github and take a look at other repositories, eg Android, Linux, Hadoop, etc.
After your done browsing, use the review group generator we created earlier to generate a group for exercise 1:
$ java Generator 1 [email protected]
[[email protected], [email protected], [email protected]]
Send an email to your review group linking to your repository. You should receive similar emails from the other members of your group. If you don’t, reach out and request one.
We "clone" a repository to make a copy we can work with locally.
The clone is aware of the repository it was cloned from, so we can push our changes back to it.
Follow Github's documentation for working with remote repositories, which describes cloning.
Use git clone
to clone the repositories of your group:
$ cd ~
$ git clone https://github.com/<github username>/<repository name>.git
Build and run them. They should generate the same review group your program did.
$ cd <repository name>
$ javac Generator.java
$ java Generator 1 [email protected]
[[email protected], [email protected], [email protected]]
To pull changes, we need to create a change somewhere other than our local repo. I'll use Github for this example.
-
In Github, navigate to your project's page
-
Navigate to your file.txt
-
Click the button with the pencil icon to edit the file
-
Make a change and click the "Commit changes" button
-
In your local terminal, run
git pull
to pull these changes into your local repository:$ git pull origin master remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:erikeldridge/cst-395-example * branch master -> FETCH_HEAD 7c5d054..0c3e437 master -> origin/master Updating 7c5d054..0c3e437 Fast-forward file.txt | 1 + 1 file changed, 1 insertion(+)
I know we only have a few example commits so far, but keep the following best-practices in mind as we go forward:
- Only commit working code; the master branch should be shippable at all times
- Prefer small commits over monolithic changes
- Do not commit dead code
- Style commit messages according to git best-practices
- Include issue tracking details when available
- git - the simple guide
- Pro Git's chapter on Git Basics
- We're using Github for this book, but Bitbucket is a comparable product