<commit_before><presentation>
  <title>Git for Sys Admins</title>
  <subtitle></subtitle>
  <author><NAME></author>
  <email><EMAIL></email>

<!--

  <slide>
    <title>Title Here</title>
    <screenshot>filename.png</screenshot>
    <image src="file.jpg" />
    <bullet></bullet>
    <code syntax="perl"><![CDATA[
    ]]></code>
    <notes>
    </notes>
  </slide>

-->

  <slide>
    <title>Overview</title>
    <bullet>Why revision control?</bullet>
    <bullet>Why git?</bullet>
    <bullet>Create a new repository</bullet>
    <bullet>Managing files</bullet>
    <bullet>Change logs</bullet>
    <bullet>Branching</bullet>
    <bullet>Merging</bullet>
    <bullet>Remote repositories</bullet>
    <bullet>A closer look at some concepts</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Why revision control?</title>
    <bullet>Track software</bullet>
    <bullet>View history</bullet>
    <bullet>Look back to find when bugs where created</bullet>
    <bullet>Reasoning behind why something is how it is</bullet>
    <bullet>Roll back changes</bullet>
    <bullet>Apply kudos for commits</bullet>
    <bullet>Redundant storage of your important stuff</bullet>
    <notes>
    Without revision control you end up with countless copies of files with no idea what is what.  Anecdote - files called readme.tt, readme.ttt, readme.tttt
    </notes>
  </slide>

  <slide>
    <title>What options?</title>
    <bullet>Lots of options...</bullet>
    <pause />
    <bullet>RCS</bullet>
    <bullet>CVS</bullet>
    <bullet>Subversion</bullet>
    <bullet>Darcs</bullet>
    <bullet>Perforce</bullet>
    <bullet>Bzr</bullet>
    <bullet>...</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Why not git?</title>
    <bullet>There are some new concepts</bullet>
    <bullet>There are sooo many commands!</bullet>
    <bullet>You can safely ignore most of those commands.</bullet>
    <bullet>When you do want to send patches as emails, the command is there.</bullet>
    <bullet>When you want to import patches from a mailbox, the command is there.</bullet>
    <bullet>You get the idea.</bullet>
  </slide>

  <slide>
    <title>Why git?</title>
    <bullet>The cool kids use it (including the Koha devs)</bullet>
    <bullet>It is fast</bullet>
    <bullet>As light weight as RCS, but <tt>much</tt> better!</bullet>
    <bullet>You can work offline</bullet>
    <bullet>Branching is trivial</bullet>
    <bullet>Merging of branches is fantastic</bullet>
    <bullet>You can even apply commits out of order</bullet>
    <bullet>Instead of just having a checkout, you have a local code repository <em>and</em> a checkout</bullet>
  </slide>

  <slide>
    <title>Local Repository - WTF?</title>
    <bullet>Hold on, local repository?</bullet>
    <bullet>Yes, git is just a bit different</bullet>
    <bullet>A local repository that you check commits into, like RCS</bullet>
    <bullet>But you can also talk to a remote repository, like CVS</bullet>
    <bullet>Actually, lots of remote repositories, not at all like CVS</bullet>
    <bullet>You can be disconnected from the network, yet still view logs and manage your repository</bullet>
    <bullet>Remotes can be on other computers, the local computer, USB sticks, etc</bullet>
    <bullet>Awesome! but we'll come back to this....</bullet>
  </slide>


  <slide>
    <title>Create a new repository</title>
    <bullet>..or, more specifically, create a <tt>local</tt> repository</bullet>
    <bullet>Use <tt>git init</tt></bullet>
    <code>
puck@dirk:/tmp/test$ git init
Initialized empty Git repository in .git/
puck@dirk:/tmp/test$ 
    </code>
    <bullet>Check the status with <tt>git status</tt></bullet>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Add</title>
    <bullet>Make some changes...</bullet>
    <code>
puck@dirk:/tmp/test$ touch super-script.pl
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add &lt;file>..." to include in what will be committed)
#
#	super-script.pl
nothing added to commit but untracked files present (use "git add" to track)
    </code>
    <bullet>Your local repository has an <tt>index</tt></bullet>
    <bullet>The index is used to prepare what you will commit</bullet>
    <bullet>Tell git about files with <tt>git add &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git add super-script.pl 
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#       new file: super-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Change an existing file</title>
    <bullet>Make some changes...</bullet>
    <code>
puck@dirk:/tmp/test$ echo DATA > super-script.pl
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#	new file:   super-script.pl
#
# Changed but not updated:
#   (use "git add &lt;file>..." to update what will be committed)
#   (use "git checkout -- &lt;file>..." to discard changes in working directory)
#
#	modified:   super-script.pl
#

    </code>
    <bullet>Tell git about files with <tt>git add &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git add super-script.pl 
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#	new file:   super-script.pl
#
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Commiting changes</title>
    <bullet>We have told git about our changes</bullet>
    <bullet>We haven't actually committed anything yet</bullet>
    <bullet>This is deliberate - so you can build up more complex commits</bullet>
    <bullet>Every change needs to be committed</bullet>
    <bullet>Commit with <tt>git commit &lt;files></tt></bullet>
    <bullet>You will be asked for a commit message</bullet>
    <code>
puck@dirk:/tmp/test$ git commit super-script.pl 
Created commit ae54011: Add a message.
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 super-script.pl
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Commiting changes - some useful options</title>
    <bullet>You don't <tt>have</tt> to add all your changes manually</bullet>
    <code>
puck@dirk:/tmp/test$ git commit -a
    </code>
    <bullet>If you don't want to use an editor...</bullet>
    <code>
puck@dirk:/tmp/test$ git commit -m 'commit message goes here'
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Permissions</title>
    <bullet>Oops, that file isn't executable</bullet>
    <bullet>Unlike <tt>some</tt> revision control systems, git is aware of file permissions</bullet>
    <code>
puck@dirk:/tmp/test$ chmod 755 super-script.pl 
puck@dirk:/tmp/test$ 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
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>


  <slide>
    <title>Managing Files - Move</title>
    <bullet>To rename a file use <tt>git mv &lt;source> &lt;dest></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git mv super-script.pl silly-script.pl
    </code>
    <bullet>Check the status</bullet>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       renamed:    super-script.pl -> silly-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <bullet>And commit the change</bullet>
    <code>
puck@dirk:/tmp/test$ git commit
Created commit fabd446: Rename the file.
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename super-script.pl => silly-script.pl (100%)
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Delete</title>
    <bullet>To delete a file use <tt>git rm &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git rm another-script.pl 
    </code>
    <bullet>Check the status</bullet>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       deleted:    another-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <bullet>And commit the change</bullet>
    <code>
puck@dirk:/tmp/test$ git commit
Created commit bd10c5f: Remove another-script.pl
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 another-script.pl
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Local Repository - Abort a change</title>
    <bullet>What if you screw things up?</bullet>
    <bullet>If you haven't committed yet, you can run <tt>git reset --hard</tt></bullet>
    <bullet>This throws away <b>all</b> local changes, except unknown files</bullet>
  </slide>

  <slide>
    <title>Local Repository - Abort a change.. more carefully</title>
    <bullet>What if you make a bogus edit?</bullet>
    <code>
uck@dirk:/tmp/test$ echo "I am sooo drunk!" > silly-script.pl 
    </code>
    <bullet> and tell git we want to commit this edit</bullet>
    <code>
puck@dirk:/tmp/test$ git add silly-script.pl 
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       modified:   silly-script.pl
#
     </code>
     <bullet>Oops</bullet>
     <bullet>Use <tt>git reset</tt> to undo the <tt>git add</tt></bullet>
     <code>
puck@dirk:/tmp/test$ git reset HEAD silly-script.pl 
silly-script.pl: needs update
     </code>
     <bullet>And <tt>git checkout</tt> to undo the edit</bullet>
     <code>
puck@dirk:/tmp/test$ git checkout silly-script.pl 
puck@dirk:/tmp/test$ git status
# On branch master
nothing to commit (working directory clean)
puck@dirk:/tmp/test$ 
    </code>
     <bullet>I actually use <tt>gitk</tt> for this</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs</title>
    <bullet>See what is going on</bullet>
    <bullet>Use <tt>git log</tt></bullet>
    <bullet>By default the output is piped into $PAGER</bullet>
<code>
<![CDATA[
puck@dirk:/tmp/test$ git log
commit bd10c5f5179b4c6b52d586cc5355e3018b3c8c37
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:08:02 2008 +1200

    Remove another-script.pl

commit cc260920d4b1aa87e000d2a52643b22b725d4922
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:07:35 2008 +1200

    Add a test script.

commit fabd44619bd37f47b9e1e193ee4ded97e64f8f4a
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:03:04 2008 +1200

    Rename the file.

commit 378af932284a01c8cb6c3de202182ecac0fa7969
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:02:24 2008 +1200

    Make it executable.

commit ae540117822f58ca7974c69fe13270959cc04f34
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:01:41 2008 +1200

    Add a message.
puck@dirk:/tmp/test$ git log | cat
commit bd10c5f5179b4c6b52d586cc5355e3018b3c8c37
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:08:02 2008 +1200

    Remove another-script.pl

commit cc260920d4b1aa87e000d2a52643b22b725d4922
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:07:35 2008 +1200

    Add a test script.

commit fabd44619bd37f47b9e1e193ee4ded97e64f8f4a
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:03:04 2008 +1200

    Rename the file.

commit 378af932284a01c8cb6c3de202182ecac0fa7969
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:02:24 2008 +1200

    Make it executable.

commit ae540117822f58ca7974c69fe13270959cc04f34
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:01:41 2008 +1200

    Add a message.
puck@dirk:/tmp/test$ 
]]>
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs</title>
    <bullet>Can specify a file or directory</bullet>
<code>
puck@dirk:/tmp/test$ git log silly-script.pl 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs - Annotate</title>
    <bullet>Show who made changes to what line</bullet>
    <bullet>Also known as the blame log</bullet>
<code>
puck@dirk:/tmp/test$ git blame silly-script.pl
puck@dirk:/tmp/test$ git blame silly-script.pl  | cat
^ae54011 super-script.pl (Andrew Ruthven 2008-05-09 17:01:41 +1200 1) #!/usr/bin/perl -w
^ae54011 super-script.pl (Andrew Ruthven 2008-05-09 17:01:41 +1200 2) 
^ae54011 super-script.pl (Andrew Ruthven 2008-05-09 17:01:41 +1200 3) print "silly script\n";
2c08faf4 silly-script.pl (Bad Coder      2008-05-09 17:18:18 +1200 4) I'm in ur code, breaking ur stuff.
puck@dirk:/tmp/test$ 
</code>
    <bullet>Who is this Bad Coder fella?</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Reverting changes </title>
    <bullet>Sometimes we want to undo a commit</bullet>
    <bullet>Many different ways, one way to leave an audit trail:</bullet>
    <bullet><tt>git revert &lt;commit ID></tt></bullet>
<code>
puck@dirk:/tmp/test$ git revert 2c08faf4
Finished one revert.
Created commit e766bfb: Revert "Break the code!"
 1 files changed, 0 insertions(+), 1 deletions(-)
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Change Logs - GUI</title>
    <bullet>Not strictly change logs, but...</bullet>
    <bullet>gitk</bullet>
    <bullet>git-gui</bullet>
    <bullet>Many more</bullet>
    <bullet> -- demo</bullet>
  </slide>

  <slide>
    <title>Branching - List</title>
    <bullet>To show branches use <tt>git branch</tt></bullet>
<code>
puck@dirk:/tmp/test$ git branch
* master
puck@dirk:/tmp/test$ 
</code>
    <bullet>Only one branch called <tt>master</tt></bullet>
  </slide>

  <slide>
    <title>Branching - Create</title>
    <bullet>Use <tt>git checkout -b &lt;new-name></tt></bullet>
<code>
puck@dirk:/tmp/test$ git checkout -b new-branch
Switched to a new branch "new-branch"
puck@dirk:/tmp/test$ git branch
  master
* new-branch
puck@dirk:/tmp/test$ 
</code>
    <bullet>Can also create a new branch without being on the source branch</bullet>
<code>
puck@dirk:/tmp/test$ git checkout -b another-branch master
Switched to a new branch "another-branch"
puck@dirk:/tmp/test$ git branch
* another-branch
  master
  new-branch
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Branching - Change Branch</title>
    <bullet>Just use <tt>git checkout</tt> without the <tt>-b</tt></bullet>
<code>
puck@dirk:/tmp/test$ git checkout new-branch
Switched to branch "new-branch"
puck@dirk:/tmp/test$ git branch
  another-branch
  master
* new-branch
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Branching - What's the deal?</title>
    <bullet>You can make commits on a branch without polluting other branches</bullet>
<code>
puck@dirk:/tmp/test$ echo "# From new-branch" >> silly-script.pl 
puck@dirk:/tmp/test$ git commit silly-script.pl 
Created commit a6ed2cf: From new-branch
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test$ 
</code>
    <bullet>Check the file, then jump to another branch, it ain't there</bullet>
<code>
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "silly script\n";
# From new-branch
puck@dirk:/tmp/test$ git checkout master
Switched to branch "master"
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "silly script\n";
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Merging - Simple Case</title>
    <bullet>Just say <tt>git merge &lt;other branch></tt></bullet>
<code>
puck@dirk:/tmp/test$ git merge new-branch
Updating e766bfb..a6ed2cf
Fast forward
 silly-script.pl |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test$ 
</code>
    <bullet>If there are no conflicts, the merge just happens</bullet>
    <bullet>Conflicts are more difficult</bullet>
  </slide>

  <slide>
    <title>Merging - With conflicts</title>
    <bullet>If there are conflicts then git will stop and let you fix it.</bullet>
    <bullet>Lots of tools to help fix things up.  Hand edit, xxdiff, smartmerge, etc</bullet>
<code>
puck@dirk:/tmp/test$ 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.
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD:silly-script.pl
print "silly script - change on master\n";
=======
print "change on new-branch - silly script\n";
>>>>>>> new-branch:silly-script.pl
# From new-branch
puck@dirk:/tmp/test$ 
</code>
    <bullet>Fix it, in this case use vi</bullet>
<code>
puck@dirk:/tmp/test$ vi silly-script.pl 
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "change on new-branch - silly script - change on master\n";
# From new-branch
</code>
    <bullet>Now that we've fixed the code, tell git that it has been fixed and commit it</bullet>
<code>
puck@dirk:/tmp/test$ git add silly-script.pl 
puck@dirk:/tmp/test$ git commit
Created commit a411f2a: Merge branch 'new-branch'
puck@dirk:/tmp/test$ 
</code>
    <bullet>In this case the commit message is automatically created</bullet>
<code>
Merge branch 'new-branch'

Conflicts:

        silly-script.pl

</code>
  </slide>

  <slide>
    <title>Merging - How does it look?</title>
    <bullet>Looking at the trees in gitk is cool.</bullet>
  </slide>

  <slide>
    <title>Remote repositories - URLs</title>
    <bullet>There are many different ways to get remote repositories, some are:</bullet>
      <bullet>HTTP</bullet>
<code>
puck@dirk:/tmp$ git clone http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
Initialized empty Git repository in /tmp/catalyst-systemsadministrator/.git/
got e8cc197ae63382e20adbedeb2491f7bd517c2ba4
walk e8cc197ae63382e20adbedeb2491f7bd517c2ba4
got 7ba4fe662265a0fcae049c2d1d34f804c7c1f623
got 1596463cebc5b4fd366775c9e9f2bfad7167a911
Getting alternates list for http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
got 35aef72bdb120b8e49b7b96b369e6fc7a9b99d51
walk 1596463cebc5b4fd366775c9e9f2bfad7167a911
Getting pack list for http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
got 3659410cbe90d1e968cc9e7921b8aa95c4848618
got d03dfdf805a54193da4a1aaf2869ff23c830606f
...
</code>
    <bullet>SSH</bullet>
<code>
puck@dirk:/tmp$ git clone git+ssh://git.catalyst.net.nz/git/private/catalyst-systemsadministrator.git
Initialized empty Git repository in /tmp/catalyst-systemsadministrator/.git/
remote: Generating pack...
remote: Done counting 453 objects.
remote: Deltifying 453 objects...
remote:  100% (453/453) done
Indexing 453 objects...
remote: Total 453 (delta 208), reused 379 (delta 169)
 100% (453/453) done
Resolving 208 deltas...
 100% (208/208) done

puck@dirk:/tmp$ 
</code>
    <bullet>Local directory (this is just a bit mad)</bullet>
<code>
puck@dirk:/tmp$ git clone test test2
Initialized empty Git repository in /tmp/test2/.git/
remote: Generating pack...
remote: Done counting 29 objects.
Deltifying 29 objects...
 100% (29/29) donete: done
remote: Total 29 (delta 4), reused 0 (delta 0)
Indexing 29 objects...
 100% (29/29) done
Resolving 4 deltas...
 100% (4/4) done
</code>
  </slide>
  <slide>
    <title>Remote repositories - Clone</title>
    <bullet>Easy to do, <tt>git clone &lt;URL> &lt;local dir></tt></bullet>
    <bullet>&lt;local dir> is optional</bullet>
    <code>
puck@dirk:/tmp/test$ cd ..
puck@dirk:/tmp$ git clone http://gitprivate.catalyst.net.nz/git-training.git
Initialized empty Git repository in /tmp/git-training/.git/
puck@dirk:/tmp$ 
    </code>
    <bullet>You now have the source code for this course, checked out</bullet>
    <code>
puck@dirk:/tmp$ cd git-training
puck@dirk:/tmp/git-training$ ls talk.xml
talk.xml
    </code>
  </slide>

  <slide>
    <title>Remote repositories - Clone local</title>
    <bullet>Easy to do, <tt>git clone &lt;URL> &lt;local dir></tt></bullet>
    <bullet>&lt;local dir> is optional</bullet>
<code>
puck@dirk:/tmp/test$ cd ..
puck@dirk:/tmp$ git clone test test2
Initialized empty Git repository in /tmp/test2/.git/
puck@dirk:/tmp$ 
</code>
    <bullet>You now made a copy of your previous work</bullet>
<code>
puck@dirk:/tmp$ cd test2
puck@dirk:/tmp/test2$ ls 
silly-script.pl
puck@dirk:/tmp/test2$ 
</code>
    <bullet>Looks familiar, how about the branches?</bullet>
<code>
puck@dirk:/tmp/test2$ git branch
* master
puck@dirk:/tmp/test2$ 
</code>
    <bullet>Only master, not the others.  Use <tt>git branch -a</tt> to see remote branches</bullet>
<code>
puck@dirk:/tmp/test2$ git branch -a
* master
  origin/HEAD
  origin/another-branch
  origin/master
  origin/new-branch
puck@dirk:/tmp/test2$
</code>
  </slide>

  <slide>
    <title>Remote repositories - Local branch</title>
    <bullet>You may want to work on a remote branch</bullet>
    <bullet>Very similar to copying local branches</bullet>
<code>
puck@dirk:/tmp/test2$ git checkout -b pucks-working origin/new-branch
Switched to a new branch "pucks-working"
puck@dirk:/tmp/test2$ git branch -a
  master
* pucks-working
  origin/HEAD
  origin/another-branch
  origin/master
  origin/new-branch
puck@dirk:/tmp/test2$ 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Remote repositories - Local changes</title>
    <bullet>Very similar work flow</bullet>
<code>
puck@dirk:/tmp/test2$ vi silly-script.pl 
puck@dirk:/tmp/test2$ cat silly-script.pl 
#!/usr/bin/perl -w

print "change on new-branch - silly script - change on master\n";
# From new-branch
# Make a change on test2.
puck@dirk:/tmp/test2$ git commit silly-script.pl 
Created commit c2f770f: Change on test2 clone.
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test2$ git push
Everything up-to-date
puck@dirk:/tmp/test2$ 
</code>
    <bullet>We we need to push our changes</bullet>
<code>
puck@dirk:/tmp/test2$ git push
updating 'refs/heads/master'
  from 2f8f119f7f197d1b6c3af53cc1aea29215702fba
  to   c2f770f85e11046187075c53d640998aa767cf7e
Generating pack...
Done counting 5 objects.
Result has 3 objects.
Deltifying 3 objects...
 100% (3/3) done
Writing 3 objects...
 100% (3/3) done
Unpacking 3 objects...
 100% (3/3) done
Total 3 (delta 1), reused 0 (delta 0)
refs/heads/master: 2f8f119f7f197d1b6c3af53cc1aea29215702fba -> c2f770f85e11046187075c53d640998aa767cf7e
puck@dirk:/tmp/test2$ 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Remote repositories - Fetch</title>
    <bullet>Lots of different approaches</bullet>
    <bullet>Some people use <tt>git pull</tt></bullet>
    <bullet>Others use <tt>git fetch</tt> then <tt>git rebase</tt></bullet>
    <bullet>Still others use stacked git</bullet>
    <bullet>I use <tt>git fetch</tt> then <tt>git rebase</tt> so I have a bit more control</bullet>
<code>
puck@dirk:/tmp/test2$ git fetch
* refs/remotes/origin/master: fast forward to branch 'master' of /tmp/test/
  old..new: 2f8f119..c2f770f
puck@dirk:/tmp/test2$ git rebase origin/master
Current branch master is up to date.
puck@dirk:/tmp/test2$ 
</code>
    <bullet>No changes required</bullet>
    <bullet>If we had local changes they'd be "replayed" on the top of the changes we'd fetched</bullet>
  </slide>


  <slide>
    <title>A closer look at some concepts</title>
    <quote>http://www.eecs.harvard.edu/~cduan/technical/git/

    A Story

    When I first started using Git, I read plenty of tutorials, as well as the user manual. Though I picked up the basic usage patterns and commands, I never felt like I grasped what was going on 'under the hood,' so to speak. Frequently this resulted in cryptic error messages, caused by my random guessing at the right command to use at a given time. These difficulties worsened as I began to need more advanced (and less well documented) features.

    After a few months, I started to understand those under-the-hood concepts. Once I did, suddenly everything made sense. I could understand the manual pages and perform all sorts of source control tasks. Everything that seemed so cryptic and obscure now was perfectly clear.

    Understanding Git

    The conclusion I draw from this is that you can only really use Git if you understand how Git works. Merely memorizing which commands you should run at what times will work in the short run, but it's only a matter of time before you get stuck or, worse, break something.

    Half of the existing resources on Git, unfortunately, take just that approach: they walk you through which commands to run when, and expect that you should do fine if you just mimic those commands. The other half does go through all the concepts, but from what I have seen, they explain Git in a manner that assumes you already understand how Git works.  </quote>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>The End</title>
    <bullet>Questions?</bullet>
    <notes>
    </notes>
  </slide>

</presentation>
<commit_msg>Cosmetic tidyup....<commit_after><presentation>
  <title>Git for Sys Admins</title>
  <subtitle></subtitle>
  <author><NAME></author>
  <email><EMAIL></email>

<!--

  <slide>
    <title>Title Here</title>
    <screenshot>filename.png</screenshot>
    <image src="file.jpg" />
    <bullet></bullet>
    <code syntax="perl"><![CDATA[
    ]]></code>
    <notes>
    </notes>
  </slide>

-->

  <slide>
    <title>Overview</title>
    <bullet>Why revision control?</bullet>
    <bullet>Why git?</bullet>
    <bullet>Create a new repository</bullet>
    <bullet>Managing files</bullet>
    <bullet>Change logs</bullet>
    <bullet>Branching</bullet>
    <bullet>Merging</bullet>
    <bullet>Remote repositories</bullet>
    <bullet>A closer look at some concepts</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Why revision control?</title>
    <bullet>Track software</bullet>
    <bullet>View history</bullet>
    <bullet>Look back to find when bugs where created</bullet>
    <bullet>Reasoning behind why something is how it is</bullet>
    <bullet>Roll back changes</bullet>
    <bullet>Apply kudos for commits</bullet>
    <bullet>Redundant storage of your important stuff</bullet>
    <notes>
    Without revision control you end up with countless copies of files with no idea what is what.  Anecdote - files called readme.tt, readme.ttt, readme.tttt
    </notes>
  </slide>

  <slide>
    <title>What options?</title>
    <bullet>Lots of options...</bullet>
    <pause />
    <bullet>RCS</bullet>
    <bullet>CVS</bullet>
    <bullet>Subversion</bullet>
    <bullet>Darcs</bullet>
    <bullet>Perforce</bullet>
    <bullet>Bzr</bullet>
    <bullet>...</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Why not git?</title>
    <bullet>There are some new concepts</bullet>
    <bullet>There are sooo many commands!</bullet>
    <bullet>You can safely ignore most of those commands.</bullet>
    <bullet>When you do want to send patches as emails, the command is there.</bullet>
    <bullet>When you want to import patches from a mailbox, the command is there.</bullet>
    <bullet>You get the idea.</bullet>
  </slide>

  <slide>
    <title>Why git?</title>
    <bullet>The cool kids use it (including the Koha devs)</bullet>
    <bullet>It is fast</bullet>
    <bullet>As light weight as RCS, but <tt>much</tt> better!</bullet>
    <bullet>You can work offline</bullet>
    <bullet>Branching is trivial</bullet>
    <bullet>Merging of branches is fantastic</bullet>
    <bullet>You can even apply commits out of order</bullet>
    <bullet>Instead of just having a checkout, you have a local code repository <em>and</em> a checkout</bullet>
  </slide>

  <slide>
    <title>Local Repository - WTF?</title>
    <bullet>Hold on, local repository?</bullet>
    <bullet>Yes, git is just a bit different</bullet>
    <bullet>A local repository that you check commits into, like RCS</bullet>
    <bullet>But you can also talk to a remote repository, like CVS</bullet>
    <bullet>Actually, lots of remote repositories, not at all like CVS</bullet>
    <bullet>You can be disconnected from the network, yet still view logs and manage your repository</bullet>
    <bullet>Remotes can be on other computers, the local computer, USB sticks, etc</bullet>
    <bullet>Awesome! but we'll come back to this....</bullet>
  </slide>


  <slide>
    <title>Create a new repository</title>
    <bullet>..or, more specifically, create a <tt>local</tt> repository</bullet>
    <bullet>Use <tt>git init</tt></bullet>
    <code>
puck@dirk:/tmp/test$ git init
Initialized empty Git repository in .git/
puck@dirk:/tmp/test$ 
    </code>
    <bullet>Check the status with <tt>git status</tt></bullet>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Add</title>
    <bullet>Make some changes...</bullet>
    <code>
puck@dirk:/tmp/test$ touch super-script.pl
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add &lt;file>..." to include in what will be committed)
#
#	super-script.pl
nothing added to commit but untracked files present (use "git add" to track)
    </code>
    <bullet>Your local repository has an <tt>index</tt></bullet>
    <bullet>The index is used to prepare what you will commit</bullet>
    <bullet>Tell git about files with <tt>git add &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git add super-script.pl 
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#       new file: super-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Change an existing file</title>
    <bullet>Make some changes...</bullet>
    <code>
puck@dirk:/tmp/test$ echo DATA > super-script.pl
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#	new file:   super-script.pl
#
# Changed but not updated:
#   (use "git add &lt;file>..." to update what will be committed)
#   (use "git checkout -- &lt;file>..." to discard changes in working directory)
#
#	modified:   super-script.pl
#

    </code>
    <bullet>Tell git about files with <tt>git add &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git add super-script.pl 
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file>..." to unstage)
#
#	new file:   super-script.pl
#
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Commiting changes</title>
    <bullet>We have told git about our changes</bullet>
    <bullet>We haven't actually committed anything yet</bullet>
    <bullet>This is deliberate - so you can build up more complex commits</bullet>
    <bullet>Every change needs to be committed</bullet>
    <bullet>Commit with <tt>git commit &lt;files></tt></bullet>
    <bullet>You will be asked for a commit message</bullet>
    <code>
puck@dirk:/tmp/test$ git commit super-script.pl 
Created commit ae54011: Add a message.
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 super-script.pl
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Commiting changes - some useful options</title>
    <bullet>You don't <tt>have</tt> to add all your changes manually</bullet>
    <code>
puck@dirk:/tmp/test$ git commit &lt;file>
    </code>
    <code>
puck@dirk:/tmp/test$ git commit -a
    </code>
    <bullet>If you don't want to use an editor...</bullet>
    <code>
puck@dirk:/tmp/test$ git commit -m 'commit message goes here'
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Permissions</title>
    <bullet>Oops, that file isn't executable</bullet>
    <bullet>Unlike <tt>some</tt> revision control systems, git is aware of file permissions</bullet>
    <code>
puck@dirk:/tmp/test$ chmod 755 super-script.pl 
puck@dirk:/tmp/test$ 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
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>


  <slide>
    <title>Managing Files - Move</title>
    <bullet>To rename a file use <tt>git mv &lt;source> &lt;dest></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git mv super-script.pl silly-script.pl
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       renamed:    super-script.pl -> silly-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <bullet>And commit the change</bullet>
    <code>
puck@dirk:/tmp/test$ git commit
Created commit fabd446: Rename the file.
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename super-script.pl => silly-script.pl (100%)
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Managing Files - Delete</title>
    <bullet>To delete a file use <tt>git rm &lt;files></tt></bullet>
    <code>
puck@dirk:/tmp/test$ git rm another-script.pl 
    </code>
    <code>
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       deleted:    another-script.pl
#
puck@dirk:/tmp/test$ 
    </code>
    <bullet>And commit the change</bullet>
    <code>
puck@dirk:/tmp/test$ git commit
Created commit bd10c5f: Remove another-script.pl
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 another-script.pl
puck@dirk:/tmp/test$ 
    </code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Local Repository - Abort a change</title>
    <bullet>What if you screw things up?</bullet>
    <bullet>If you haven't committed yet, you can run <tt>git reset --hard</tt></bullet>
    <bullet>This throws away <b>all</b> local changes, except unknown files</bullet>
  </slide>

  <slide>
    <title>Local Repository - Abort a change.. more carefully</title>
    <bullet>What if you make a bogus edit?</bullet>
    <code>
uck@dirk:/tmp/test$ echo "I am sooo drunk!" > silly-script.pl 
    </code>
    <bullet> and tell git we want to commit this edit</bullet>
    <code>
puck@dirk:/tmp/test$ git add silly-script.pl 
puck@dirk:/tmp/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file>..." to unstage)
#
#       modified:   silly-script.pl
#
     </code>
     <bullet>Oops</bullet>
     <bullet>Use <tt>git reset</tt> to undo the <tt>git add</tt></bullet>
     <code>
puck@dirk:/tmp/test$ git reset HEAD silly-script.pl 
silly-script.pl: needs update
     </code>
     <bullet>And <tt>git checkout</tt> to undo the edit</bullet>
     <code>
puck@dirk:/tmp/test$ git checkout silly-script.pl 
puck@dirk:/tmp/test$ git status
# On branch master
nothing to commit (working directory clean)
puck@dirk:/tmp/test$ 
    </code>
     <bullet>I actually use <tt>gitk</tt> for this</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs</title>
    <bullet>See what is going on</bullet>
    <bullet>Use <tt>git log</tt></bullet>
    <bullet>By default the output is piped into $PAGER</bullet>
<code>
<![CDATA[
puck@dirk:/tmp/test$ git log
commit bd10c5f5179b4c6b52d586cc5355e3018b3c8c37
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:08:02 2008 +1200

    Remove another-script.pl

commit cc260920d4b1aa87e000d2a52643b22b725d4922
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:07:35 2008 +1200

    Add a test script.

commit fabd44619bd37f47b9e1e193ee4ded97e64f8f4a
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:03:04 2008 +1200

    Rename the file.

commit 378af932284a01c8cb6c3de202182ecac0fa7969
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:02:24 2008 +1200

    Make it executable.

commit ae540117822f58ca7974c69fe13270959cc04f34
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:01:41 2008 +1200

    Add a message.
puck@dirk:/tmp/test$ git log | cat
commit bd10c5f5179b4c6b52d586cc5355e3018b3c8c37
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:08:02 2008 +1200

    Remove another-script.pl

commit cc260920d4b1aa87e000d2a52643b22b725d4922
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:07:35 2008 +1200

    Add a test script.

commit f<PASSWORD>
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:03:04 2008 +1200

    Rename the file.

commit 378af932284a01c8cb6c3de202182ecac0fa7969
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:02:24 2008 +1200

    Make it executable.

commit ae540117822f58ca7974c69fe13270959cc04f34
Author: <NAME> <<EMAIL>>
Date:   Fri May 9 17:01:41 2008 +1200

    Add a message.
puck@dirk:/tmp/test$ 
]]>
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs</title>
    <bullet>Can specify a file or directory</bullet>
<code>
puck@dirk:/tmp/test$ git log silly-script.pl 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Change Logs - Annotate</title>
    <bullet>Show who made changes to what line</bullet>
    <bullet>Also known as the blame log</bullet>
<code>
puck@dirk:/tmp/test$ git blame silly-script.pl
puck@dirk:/tmp/test$ git blame silly-script.pl  | cat
^ae54011 super-script.pl (<NAME> 2008-05-09 17:01:41 +1200 1) #!/usr/bin/perl -w
^ae54011 super-script.pl (<NAME> 2008-05-09 17:01:41 +1200 2) 
^ae54011 super-script.pl (<NAME> 2008-05-09 17:01:41 +1200 3) print "silly script\n";
2c08faf4 silly-script.pl (Bad Coder      2008-05-09 17:18:18 +1200 4) I'm in ur code, breaking ur stuff.
puck@dirk:/tmp/test$ 
</code>
    <bullet>Who is this Bad Coder fella?</bullet>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Reverting changes </title>
    <bullet>Sometimes we want to undo a commit</bullet>
    <bullet>Many different ways, one way to leave an audit trail:</bullet>
    <bullet><tt>git revert &lt;commit ID></tt></bullet>
<code>
puck@dirk:/tmp/test$ git revert 2c08faf4
Finished one revert.
Created commit e766bfb: Revert "Break the code!"
 1 files changed, 0 insertions(+), 1 deletions(-)
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Change Logs - GUI</title>
    <bullet>Not strictly change logs, but...</bullet>
    <bullet>gitk</bullet>
    <bullet>git-gui</bullet>
    <bullet>Many more</bullet>
    <bullet> -- demo</bullet>
  </slide>

  <slide>
    <title>Branching - List</title>
    <bullet>To show branches use <tt>git branch</tt></bullet>
<code>
puck@dirk:/tmp/test$ git branch
* master
puck@dirk:/tmp/test$ 
</code>
    <bullet>Only one branch called <tt>master</tt></bullet>
  </slide>

  <slide>
    <title>Branching - Create</title>
    <bullet>Use <tt>git checkout -b &lt;new-name></tt></bullet>
<code>
puck@dirk:/tmp/test$ git checkout -b new-branch
Switched to a new branch "new-branch"
puck@dirk:/tmp/test$ git branch
  master
* new-branch
puck@dirk:/tmp/test$ 
</code>
    <bullet>Can also create a new branch without being on the source branch</bullet>
<code>
puck@dirk:/tmp/test$ git checkout -b another-branch master
Switched to a new branch "another-branch"
puck@dirk:/tmp/test$ git branch
* another-branch
  master
  new-branch
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Branching - Change Branch</title>
    <bullet>Just use <tt>git checkout</tt> without the <tt>-b</tt></bullet>
<code>
puck@dirk:/tmp/test$ git checkout new-branch
Switched to branch "new-branch"
puck@dirk:/tmp/test$ git branch
  another-branch
  master
* new-branch
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Branching - What's the deal?</title>
    <bullet>You can make commits on a branch without polluting other branches</bullet>
<code>
puck@dirk:/tmp/test$ echo "# From new-branch" >> silly-script.pl 
puck@dirk:/tmp/test$ git commit silly-script.pl 
Created commit a6ed2cf: From new-branch
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test$ 
</code>
    <bullet>Check the file, then jump to another branch, it ain't there</bullet>
<code>
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "silly script\n";
# From new-branch
puck@dirk:/tmp/test$ git checkout master
Switched to branch "master"
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "silly script\n";
puck@dirk:/tmp/test$ 
</code>
  </slide>

  <slide>
    <title>Merging - Simple Case</title>
    <bullet>Just say <tt>git merge &lt;other branch></tt></bullet>
<code>
puck@dirk:/tmp/test$ git merge new-branch
Updating e766bfb..a6ed2cf
Fast forward
 silly-script.pl |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test$ 
</code>
    <bullet>If there are no conflicts, the merge just happens</bullet>
    <bullet>Conflicts are more difficult</bullet>
  </slide>

  <slide>
    <title>Merging - With conflicts</title>
    <bullet>If there are conflicts then git will stop and let you fix it.</bullet>
    <bullet>Lots of tools to help fix things up.  Hand edit, xxdiff, smartmerge, etc</bullet>
<code>
puck@dirk:/tmp/test$ 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.
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD:silly-script.pl
print "silly script - change on master\n";
=======
print "change on new-branch - silly script\n";
>>>>>>> new-branch:silly-script.pl
# From new-branch
puck@dirk:/tmp/test$ 
</code>
    <bullet>Fix it, in this case use vi</bullet>
<code>
puck@dirk:/tmp/test$ vi silly-script.pl 
puck@dirk:/tmp/test$ cat silly-script.pl 
#!/usr/bin/perl -w

print "change on new-branch - silly script - change on master\n";
# From new-branch
</code>
    <bullet>Now that we've fixed the code, tell git that it has been fixed and commit it</bullet>
<code>
puck@dirk:/tmp/test$ git add silly-script.pl 
puck@dirk:/tmp/test$ git commit
Created commit a411f2a: Merge branch 'new-branch'
puck@dirk:/tmp/test$ 
</code>
    <bullet>In this case the commit message is automatically created</bullet>
<code>
Merge branch 'new-branch'

Conflicts:

        silly-script.pl

</code>
  </slide>

  <slide>
    <title>Merging - How does it look?</title>
    <bullet>Looking at the trees in gitk is cool.</bullet>
  </slide>

  <slide>
    <title>Remote repositories - URLs</title>
    <bullet>There are many different ways to get remote repositories, some are:</bullet>
      <bullet>HTTP</bullet>
<code>
puck@dirk:/tmp$ git clone http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
Initialized empty Git repository in /tmp/catalyst-systemsadministrator/.git/
got e8cc197ae63382e20adbedeb2491f7bd517c2ba4
walk e8cc197ae63382e20adbedeb2491f7bd517c2ba4
got 7ba4fe662265a0fcae049c2d1d34f804c7c1f623
got 1596463cebc5b4fd366775c9e9f2bfad7167a911
Getting alternates list for http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
got 35aef72bdb120b8e49b7b96b369e6fc7a9b99d51
walk 1596463cebc5b4fd366775c9e9f2bfad7167a911
Getting pack list for http://gitprivate.catalyst.net.nz/catalyst-systemsadministrator.git
got 3659410cbe90d1e968cc9e7921b8aa95c4848618
got d03dfdf805a54193da4a1aaf2869ff23c830606f
...
</code>
    <bullet>SSH</bullet>
<code>
puck@dirk:/tmp$ git clone git+ssh://git.catalyst.net.nz/git/private/catalyst-systemsadministrator.git
Initialized empty Git repository in /tmp/catalyst-systemsadministrator/.git/
remote: Generating pack...
remote: Done counting 453 objects.
remote: Deltifying 453 objects...
remote:  100% (453/453) done
Indexing 453 objects...
remote: Total 453 (delta 208), reused 379 (delta 169)
 100% (453/453) done
Resolving 208 deltas...
 100% (208/208) done

puck@dirk:/tmp$ 
</code>
    <bullet>Local directory (this is just a bit mad)</bullet>
<code>
puck@dirk:/tmp$ git clone test test2
Initialized empty Git repository in /tmp/test2/.git/
remote: Generating pack...
remote: Done counting 29 objects.
Deltifying 29 objects...
 100% (29/29) donete: done
remote: Total 29 (delta 4), reused 0 (delta 0)
Indexing 29 objects...
 100% (29/29) done
Resolving 4 deltas...
 100% (4/4) done
</code>
  </slide>
  <slide>
    <title>Remote repositories - Clone</title>
    <bullet>Easy to do, <tt>git clone &lt;URL> &lt;local dir></tt></bullet>
    <bullet>&lt;local dir> is optional</bullet>
    <code>
puck@dirk:/tmp/test$ cd ..
puck@dirk:/tmp$ git clone http://gitprivate.catalyst.net.nz/git-training.git
Initialized empty Git repository in /tmp/git-training/.git/
puck@dirk:/tmp$ 
    </code>
    <bullet>You now have the source code for this course, checked out</bullet>
    <code>
puck@dirk:/tmp$ cd git-training
puck@dirk:/tmp/git-training$ ls talk.xml
talk.xml
    </code>
  </slide>

  <slide>
    <title>Remote repositories - Clone local</title>
    <bullet>Easy to do, <tt>git clone &lt;URL> &lt;local dir></tt></bullet>
    <bullet>&lt;local dir> is optional</bullet>
<code>
puck@dirk:/tmp/test$ cd ..
puck@dirk:/tmp$ git clone test test2
Initialized empty Git repository in /tmp/test2/.git/
puck@dirk:/tmp$ 
</code>
    <bullet>You now made a copy of your previous work</bullet>
<code>
puck@dirk:/tmp$ cd test2
puck@dirk:/tmp/test2$ ls 
silly-script.pl
puck@dirk:/tmp/test2$ 
</code>
    <bullet>Looks familiar, how about the branches?</bullet>
<code>
puck@dirk:/tmp/test2$ git branch
* master
puck@dirk:/tmp/test2$ 
</code>
    <bullet>Only master, not the others.  Use <tt>git branch -a</tt> to see remote branches</bullet>
<code>
puck@dirk:/tmp/test2$ git branch -a
* master
  origin/HEAD
  origin/another-branch
  origin/master
  origin/new-branch
puck@dirk:/tmp/test2$
</code>
  </slide>

  <slide>
    <title>Remote repositories - Local branch</title>
    <bullet>You may want to work on a remote branch</bullet>
    <bullet>Very similar to copying local branches</bullet>
<code>
puck@dirk:/tmp/test2$ git checkout -b pucks-working origin/new-branch
Switched to a new branch "pucks-working"
puck@dirk:/tmp/test2$ git branch -a
  master
* pucks-working
  origin/HEAD
  origin/another-branch
  origin/master
  origin/new-branch
puck@dirk:/tmp/test2$ 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Remote repositories - Local changes</title>
    <bullet>Very similar work flow</bullet>
<code>
puck@dirk:/tmp/test2$ vi silly-script.pl 
puck@dirk:/tmp/test2$ cat silly-script.pl 
#!/usr/bin/perl -w

print "change on new-branch - silly script - change on master\n";
# From new-branch
# Make a change on test2.
puck@dirk:/tmp/test2$ git commit silly-script.pl 
Created commit c2f770f: Change on test2 clone.
 1 files changed, 1 insertions(+), 0 deletions(-)
puck@dirk:/tmp/test2$ git push
Everything up-to-date
puck@dirk:/tmp/test2$ 
</code>
    <bullet>We we need to push our changes</bullet>
<code>
puck@dirk:/tmp/test2$ git push
updating 'refs/heads/master'
  from 2f8f119f7f197d1b6c3af53cc1aea29215702fba
  to   c2f770f85e11046187075c53d640998aa767cf7e
Generating pack...
Done counting 5 objects.
Result has 3 objects.
Deltifying 3 objects...
 100% (3/3) done
Writing 3 objects...
 100% (3/3) done
Unpacking 3 objects...
 100% (3/3) done
Total 3 (delta 1), reused 0 (delta 0)
refs/heads/master: 2f8f119f7f197d1b6c3af53cc1aea29215702fba -> c2f770f85e11046187075c53d640998aa767cf7e
puck@dirk:/tmp/test2$ 
</code>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>Remote repositories - Fetch</title>
    <bullet>Lots of different approaches</bullet>
    <bullet>Some people use <tt>git pull</tt></bullet>
    <bullet>Others use <tt>git fetch</tt> then <tt>git rebase</tt></bullet>
    <bullet>Still others use stacked git</bullet>
    <bullet>I use <tt>git fetch</tt> then <tt>git rebase</tt> so I have a bit more control</bullet>
<code>
puck@dirk:/tmp/test2$ git fetch
* refs/remotes/origin/master: fast forward to branch 'master' of /tmp/test/
  old..new: 2f8f119..c2f770f
puck@dirk:/tmp/test2$ git rebase origin/master
Current branch master is up to date.
puck@dirk:/tmp/test2$ 
</code>
    <bullet>No changes required</bullet>
    <bullet>If we had local changes they'd be "replayed" on the top of the changes we'd fetched</bullet>
  </slide>


  <slide>
    <title>A closer look at some concepts</title>
    <quote>http://www.eecs.harvard.edu/~cduan/technical/git/

    A Story

    When I first started using Git, I read plenty of tutorials, as well as the user manual. Though I picked up the basic usage patterns and commands, I never felt like I grasped what was going on 'under the hood,' so to speak. Frequently this resulted in cryptic error messages, caused by my random guessing at the right command to use at a given time. These difficulties worsened as I began to need more advanced (and less well documented) features.

    After a few months, I started to understand those under-the-hood concepts. Once I did, suddenly everything made sense. I could understand the manual pages and perform all sorts of source control tasks. Everything that seemed so cryptic and obscure now was perfectly clear.

    Understanding Git

    The conclusion I draw from this is that you can only really use Git if you understand how Git works. Merely memorizing which commands you should run at what times will work in the short run, but it's only a matter of time before you get stuck or, worse, break something.

    Half of the existing resources on Git, unfortunately, take just that approach: they walk you through which commands to run when, and expect that you should do fine if you just mimic those commands. The other half does go through all the concepts, but from what I have seen, they explain Git in a manner that assumes you already understand how Git works.  </quote>
    <notes>
    </notes>
  </slide>

  <slide>
    <title>The End</title>
    <bullet>Questions?</bullet>
    <notes>
    </notes>
  </slide>

</presentation>

{'fraction_non_alphanumeric': 0.13513029639944302, 'fraction_numerical': 0.04064054107817784, 'mean_word_length': 3.6349806380232343, 'pattern_counts': {'":': 0, '<': 1379, '<?xml version=': 0, '>': 1458, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '690568', 'n_tokens_mistral': 19336, 'n_tokens_neox': 17400, 'n_words': 5258}