## Why use revision control software?
#### You (should) want it if...
* You are sick of keeping *.bak files
* You might ever want to look at how something used to be
* You might ever want to know why something changed
* You might like to review what you have just changed
## Why use revision control software?
#### You need it if...
* You are working with other people who use it
* You want to maintain multiple versions of the same thing
* You want to work on separate changes at the "same time"
* You need to make a single change which covers several files - and keep things in sync
## What does revision control provide?
* Track changes (to almost anything)
* View history
* Look back to find when bugs were created
* Find the reasoning behind why something is how it is
* Roll back changes
* Apply kudos for effort
* Backups of your important stuff
## What options are there?
* RCS
* CVS
* Subversion
* Darcs
* Perforce
* Bzr
* ...
## Why should you use Git?
* It is fast
* Branching is trivial
* Merging of branches actually makes sense
* You can be disconnected from the network, yet still continue working
* It does not dictate your workflow
* [It protects your data](http://git-scm.com/about/info-assurance)
* Once you master the concepts, you can do some really creative (and useful!) stuff
* The cool kids use it
## Managing Files - Add
Make some changes...
```bash
$ touch super-script.pl
```
```bash
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# super-script.pl
nothing added to commit but untracked files present (use "git add" to track)
```
## Tell Git to track those files
Use ```git add```
```bash
$ git add super-script.pl
```
```bash
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: super-script.pl
#
```
## Change an existing file
Make some changes...
```bash
$ echo DATA > super-script.pl
```
```bash
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: super-script.pl
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: super-script.pl
#
```
## Change an existing file
We need to tell Git that you intend to commit the checked out
version, with ```git add```
```bash
$ git add super-script.pl
```
```bash
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: super-script.pl
#
```
## Committing changes
We need to commit our changes to make them permanent.
Commit with ```git commit```
```bash
$ git commit super-script.pl
Created commit ae54011: Add a message.
1 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 super-script.pl
```
You will be stuck in an editor so you can input a commit message
Normally, you WILL make your commit message meaningful
We have told git about our changes, but
we haven't actually committed anything yet.
This is deliberate - so you can build up more complex commits.
## Committing changes - some options
You don't have to ```git add``` all your changes manually
```bash
$ git commit <file>
```
```bash
$ git commit -a
```
You can have an easier editor...
```bash
$ EDITOR=gedit git commit -a
```
You don't have to use an editor at all...
```bash
$ git commit -m 'commit message goes here'
```
## Managing Files - Permissions
Oops, that file isn't executable
```bash
$ chmod 755 super-script.pl
```
```bash
$ git commit super-script.pl
Created commit 378af93: Make it executable.
0 files changed, 0 insertions(+), 0 deletions(-)
mode change 100644 => 100755 super-script.pl
```
## Managing Files - Move
To rename a file use ```git mv```
```bash
$ git mv super-script.pl silly-script.pl
```
```bash
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: super-script.pl -> silly-script.pl
#
```
This has changed our checkout, and the index, so we are ready to
commit the change
```bash
$ git commit
Created commit fabd446: Rename the file.
1 files changed, 0 insertions(+), 0 deletions(-)
rename super-script.pl => silly-script.pl (100%)
```
## Managing Files - Delete
To delete a file use ```git rm```
```bash
# This won't actually work, because we haven't
# created "another-script.pl"
# ... but you can try it, if you like....
$ git rm -f another-script.pl
```
```bash
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: another-script.pl
#
```
And commit the change
```bash
$ git commit
Created commit bd10c5f: Remove another-script.pl
0 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 another-script.pl
```
## Branching - List
To show branches use ```git branch```
```bash
$ git branch
* master
```
Only one branch, called ```master```
The '*' indicates that it is your current branch
You can also use 'git status'
## Branching - Create
Use ```git branch``` (or ```git checkout -b```)
```bash
$ git checkout -b new-branch
Switched to a new branch "new-branch"
```
Will create "new-branch", and check it out for you
```bash
$ git branch
master
* new-branch
```
mention that 'git checkout' is a convenience interface
...it does several things in one step
## Branching - Create somewhere else
By default a new branch will be created at the commit you
already have checked out
You can also create a new branch at another commit
```bash
$ git checkout -b another-branch master
Switched to a new branch "another-branch"
```
```bash
$ git branch
* another-branch
master
new-branch
```
Here, the checkout command is actually doing 3 things
- go the the master branch
- make a branch there (callled 'another-branch')
- checkout the 'another-branch' branch
## Branching - Change Branch
Use ```git checkout```
```bash
$ git checkout new-branch
Switched to branch "new-branch"
```
```bash
$ git branch
another-branch
master
* new-branch
```
Don't forget to see how this is shown in ```gitk```
## Branching - What's the deal?
```bash
# Make a change to a file (and commit that change)
$ echo "... From new-branch" >> silly-script.pl
$ git commit silly-script.pl
Created commit a6ed2cf: From new-branch
1 files changed, 1 insertions(+), 0 deletions(-)
```
```bash
# Check the file..
$ cat silly-script.pl
DATA
... From new-branch
```
```bash
# Jump to another branch
$ git checkout master
Switched to branch "master"
```
```bash
# The text we added ain't there
$ cat silly-script.pl
DATA
```
## Branching - Why?
* Many (most) projects have a branch for each release
* Branches are useful for experimental features / refactoring
* Branches happen (without even trying) when several people try
to work on the same project - but I'll explain that soon ;)
It is useful to think of branches as an 'alternative reality'
## Merging - Simple Case
You should now be on the master branch
```bash
$ git status
# On branch master
nothing to commit (working directory clean)
```
Use ```git merge```
```bash
$ git merge new-branch
Updating e766bfb..a6ed2cf
Fast forward
silly-script.pl | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
```
In this case, we have done a ```fast forward``` merge
If there are no conflicts, this may make a new commit object
use ```gitk``` to see what happened
* We are merging changes *IN*, from somewhere else
* explain the fast forward bit
* talk about merges being line by line, so not for binary data
## Merging - get ready for a conflict
Conflicts are more difficult (lets create one)
```bash
# Make a change to a file, commit that change to 'master'
$ echo "New value for data" > silly-script.pl
$ git commit -a -m 'update script with a new value'
# Change branches, make a change, and commit
$ git checkout new-branch
$ echo "different value for data" > silly-script.pl
$ git commit -a -m 'update script with a different value'
# Go back to the master branch, if we try to merge - there
# will be a problem!
$ git checkout master
```
Sorry about the wall of text!
Also, explain the fast forward bit
## Merging - you can't do that
If there is a conflict then git will stop and make you fix it.
```bash
$ git merge new-branch
Auto-merged silly-script.pl
CONFLICT (content): Merge conflict in silly-script.pl
Automatic merge failed; fix conflicts and then commit the result.
```
```bash
$ git status
# On branch master
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: silly-script.pl
#
no changes added to commit (use "git add" and/or "git commit -a")
```
```bash
$ cat silly-script.pl
<<<<<<< HEAD:silly-script.pl
New value for data
=======
different value for data
>>>>>>> new-branch:silly-script.pl
```
## Merging - Fixing conflicts
Lots of tools to help fix things up. Hand edit, xxdiff,
smartmerge, etc
We'll just fix it by editing the file
```bash
$ gedit silly-script.pl
$ cat silly-script.pl
New, different value for data
```
But Git still won't allow us to continue...
```bash
$ git commit
U silly-script.pl
fatal: 'commit' is not possible because you have unmerged files.
Please, fix them up in the work tree, and then use 'git add/rm <file>' as
appropriate to mark resolution and make a commit, or use 'git commit -a'.
```
## Merging - Success at last
We need to tell Git that it has been fixed before we commit
```bash
$ git add silly-script.pl
$ git commit
Created commit a411f2a: Merge branch 'new-branch'
```
In this case the commit message is automatically created, but
you can edit it if you want.
```bash
Merge branch 'new-branch'
Conflicts:
silly-script.pl
```
## Merging - How does it look?
Looking at the trees in gitk helps you understand stuff.
```bash
gitk
```
## Creating Repositories - Revisited
We already know how to create a new repositry
```bash
$ git init
Initialized empty Git repository in .git/
```
...but normally, you want to join in with an existing project
## Clone an existing repository
In practise, you're more likely to use ```git clone```
To check out the source code of a random project
```bash
$ cd /tmp
```
```bash
$ git clone https://github.com/libgit2/libgit2
Cloning into libget2...
remote: Counting objects: 90, done.
remote: Compressing objects: 100% (43/43), done.
remote: Total 90 (delta 44), reused 90 (delta 44)
Receiving objects: 100% (90/90), 31.62 KiB, done.
Resolving deltas: 100% (44/44), done.
```
```bash
$ cd libget2
```
```bash
$ ls
```
```bash
$ gitk
```
git remote
git remote -v
## Remote repositories - URLs
Clone an existing repository via HTTP
```bash
$ git clone http://git.catalyst.net.nz/git.git
```
Clone an existing repository via SSH
```bash
$ git clone ssh://git.catalyst.net.nz/git/public/git.git
```
Clone an existing local repository (this is just a bit mad)
```bash
$ git clone test test2
```
## Remote branches
Remote branches are references (pointers) to the state of
branches in your remote repositories.
They're local branches
that you can't move; they're moved automatically for you
whenever you do any network communication.
Remote branches act
as bookmarks to remind you where the branches on your remote
repositories were the last time you connected to them.
## Origin
You can see all branches (including the remote ones) with the
```git branch``` command
```bash
$ git branch -a
* master
remotes/origin/master
```
origin is not special
you don't need to type 'remotes' to refer to these branches