Skip to content

Commit

Permalink
More detail in second chapter
Browse files Browse the repository at this point in the history
Added outline of other chapters and other helper files
  • Loading branch information
Ben Lynn authored and Ben Lynn committed Aug 31, 2007
1 parent b1b1103 commit f32ad24
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 40 deletions.
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
target: book.html
.PHONY: target clean

TXTFILES=intro.txt basic.txt
target: book book.html

TXTFILES=intro.txt basic.txt clone.txt branch.txt

book.xml: $(TXTFILES)
./bookmake $^ > book.xml
cat $^ | sed 's/<tt>/<command>/g' | sed 's/<\/tt>/<\/command>/g' | ./bookmake > book.xml

book: book.xml
xmlto -m custom-html.xsl -o book html book.xml
-ls book/*.html | xargs -n 1 tidy -utf8 -m -i -q
./makeover

book.html: book.xml
xmlto -m custom-nochunks.xsl html-nochunks $^
Expand Down
61 changes: 40 additions & 21 deletions basic.txt
Original file line number Diff line number Diff line change
@@ -1,52 +1,71 @@
= Basic Git Tricks =
= Basic Tricks =

Rather than diving into a sea of Git commands, use these elementary examples to get your feet wet. Despite their simplicity, each of them are useful in real life.

== Instant Backup ==

When I'm about to attempt something drastic I like to save the current state, so I can go back and try again should things go awry.

$ git-init
$ git-add .
$ git-commit -m "Initial commit"
$ git-commit -m "my first backup"

to take a snapshot of all files in the current directory.
Then if something goes wrong type

$ git-reset --hard

to go back to where you were. To save the state again, type <command>git-commit -a</command> and provide a description.
$ git-checkout HEAD .

One benefit to doing this instead of simply copying files is that with Git's hash chaining, you can tell if a backup gets corrupted.
to go back to where you were. To save the state again, you can type

== Undo/Redo History ==
$ git-commit -a -m "another backup"

More generally, you can do the above, and every so often "save the game" by typing
=== Adding, Deleting, Renaming Files ===

$ git-commit -a -m "description of current state"
The above will only keep track of the files that were present when you first ran <tt>git-add</tt>. If you add new files to the directory, you'll have to tell Git:

Note if you want to keep track of newly added files or forget about deleted files you'll need to first run <command>git-add</command> or <command>git-delete</command> accordingly.
$ git-add NEWFILES...

Typing git-log shows you a list of recent commits, and their SHA1 hashes. Then typing
Similarly, if you want Git to forget about certain files, maybe because you've deleted them

$ git-commit -a
$ git-revert SHA1_HASH
$ git-rm OLDFILES...

will restore the state to the commit with the given hash. You might like to use something like the following instead:
Renaming a file is the same as removing the old name and adding the new name. There's also the shortcut <tt>git-mv</tt> which has the same syntax as the <tt>mv</tt> command. For example:

$ git-revert "@{10 minutes ago}"
$ git-mv OLDFILE NEWFILE

You can undo the undo: type git-log and you'll see that the other commits you made are still there.
== Advanced Undo/Redo ==

Typing
Typing <tt>git-log</tt> shows you a list of recent commits, and their SHA1 hashes. Then typing:

$ git-checkout SHA1_HASH .

loads a saved state without recording the fact that you've gone back to an old state. This is sometimes what you want.
will load the previous state with the given hash.
Don't like working with hashes? Then use:

$ git-checkout "@{10 minutes ago}" .

Other time specifications work too. Or you can ask for the 5th-last saved state:

$ git-checkout "@{5}" .

In some circumstances, it is preferable to type:

$ git-commit -a
$ git-revert SHA1_HASH

This appears to have the same affect, but <tt>git-log</tt> reveals that the fact that you loaded an old saved state has been recorded as new commit. In other words, you can have Git track you when you undo and redo.

Lastly, other times you might want:

$ git-reset --hard SHA1_HASH

which restores the state to a given commit but also erases all newer commits from the record permanently.

To take the computer game analogy again, git-checkout is like loading a game, git-revert is like loading a game and recording this fact as another saved game, and git-reset --hard is like loading an old save and deleting all saved games newer than the one just loaded.
To take the computer game analogy again, <tt>git-checkout</tt> is like loading a game, <tt>git-revert</tt> is like loading a game and recording this fact as another saved game, and <tt>git-reset --hard</tt> is like loading an old save and deleting all saved games newer than the one just loaded.

== Synchronize Files Between Computers ==
== Sync Computers ==

This is the reason I first used Git. I can make tarballs or use rsync to do backups. The problem was sometimes I'd edit on my laptop, other times on my desktop, and they may not have talked to each other in between.
This is the reason I first used Git. I can tolerate making tarballs or using <tt>rsync</tt> for backups. The problem was sometimes I'd edit on my laptop, other times on my desktop, and they may not have talked to each other in between.

Initialize a Git repository and commit your files as above on one machine. Then on the other:

Expand Down
11 changes: 8 additions & 3 deletions bookmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ echo '<?xml version="1.0" encoding="utf-8"?>
<copyright><year>2007</year><holder>Ben Lynn</holder></copyright>
</bookinfo>'

for FILE in $*; do
./wiki2xml $FILE
done
if [ $# -gt 0 ]; then
for FILE in $*; do
./wiki2xml $FILE
done
else
./wiki2xml
fi

echo '</book>'
56 changes: 56 additions & 0 deletions branch.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
= Branch Magic =
Cheap Context Switching

== The Boss Key ==

Ever play one of those games where you could hit a special key combination at
any time, and the screen would instantly display a spreadsheet or something? So if the boss walked in the office while you were playing the game you could quickly hide this fact?

In some directory, edit a text file and write "I'm smarter than my boss".
Create a Git repository, that is, <tt>git-init ; git-add . ; git-commit -m "Initial commit"</tt>. Then type

$ git checkout -b boss

Edit the text file to say "My boss is smarter than me", and type <tt>git-commit -a</tt>. Now you can switch between the two versions of the file with

$ git branch master # see original version of the file

and

$ git branch boss # see version of the file suitable for boss' eyes

One can imagine reasons to use this that have nothing to do with source code management. Perhaps you have a program that reads data from a certain directory, and every now and then you'd like to switch the data back and forth without reconfiguring the program.

== Dirty Work ==

TODO

== Quick Fixes ==

TODO

== Working While Being Reviewed ==

Some projects require your code to be reviewed before you can submit it. To make life easier for those reviewing your code, if you have a big change to make you might break it into two or more parts, and get each parts separately reviewed.

What if the second part cannot be written until the first part is approved and checked in? In many version control systems, you'd have to send the first part to the reviewers, and then wait until it has been approved before starting on the second part.

Actually that's not quite true, but in many systems editing part 2 before part 1 had been submitted involves a lot of suffering and hardship. In Git, branching and merging are painless. So after you've committed the first part and sent it for review:

$ git checkout -b part2

Next, code the second part of the big change while you're waiting for the first part to be accepted. When the first part is approved and submitted,

$ git branch master
$ git merge part2
$ git branch -d part2

and the second part of the change is ready to review.

But wait! What if it wasn't that simple? Say you made a mistake in the first part, which you have to correct before submitting. No problem! First, switch back to the master branch with <tt>git branch master</tt>. Fix the issue with the first part of the change and hope it gets approved. If not we simply repeat this step.

Eventually, once the first part has been approved and submitted:

$ git merge part2

and again, the second part is ready to be reviewed.
52 changes: 52 additions & 0 deletions clone.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
= Cloning Around =

== Classic Source Control ==

Copy your project to a directory in your main server. Initialize a Git
repository: <tt>git init ; git add . ; git commit -m "Initial commit"</tt>.

To check out source, a developer types

$ git clone git+ssh://main.server/directory

After making changes, the code is checked in to the main server by:

$ git commit -a
$ git push

If the main server has been updated, the latest version needs to be checked out before the push. To sync to the latest version:

$ git commit -a
$ git pull

== Forking a Project ==

Sick of the way a project is being run? Think you could do a better job?

First, on your server:

$ git clone git+ssh://main.server/directory

Then tell everyone to check out your fork of the project at your server.

At any later time, you can merge in the changes from the original project with:

$ git pull

== Ultimate Backups ==

How would you like multiple tamper-proof geographically diverse redundant archives?

TODO

== Guerilla Version Control ==

TODO

== Working On Features In Parallel ==

TODO

== Source Control Engine Tools and Utilities ==

TODO
37 changes: 37 additions & 0 deletions find_selflink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// From my own website(!)
//TODO: only do this for links in the table of contents menu

function find_selflink() {
var a = document.links;
var i = 0;
while (i < a.length) {
if (a[i].href == document.URL) {
var c;
var j;
var s_new = document.createElement("span");
s_new.className = "currentlink";
c = a[i].childNodes;
for (j=0; j<c.length; j++) {
s_new.appendChild(c[j]);
}
a[i].parentNode.replaceChild(s_new, a[i]);
} else {
i++;
}

/*
if (a[i].href == document.URL) {
a[i].className = "currentlink";
if (0) {
var s_new = document.createElement("span");
s_new.className = "currentlink";
s_new.appendChild(a[i]);
a[i].parentNode.replaceChild(s_new, a[i]);
}
}
i++;
*/
}
}

find_selflink();
18 changes: 9 additions & 9 deletions intro.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
= Introduction to Version Control =
= Introduction =

I'll use an analogy to introduce version control, also termed revision control, source control, or source code management.
See [[http://en.wikipedia.org/wiki/Revision_control][the Wikipedia entry on revision control]] for a normal explanation.

== Work is Play ==

I've played computer games almost all my life. In contrast only started using version control systems as an adult. Not surprisingly, I'm a lot more familiar with video game concepts than version control ones. I'm certain I'm not alone.
I've played computer games almost all my life. In contrast I only started using version control systems as an adult. I suspect I'm not alone, and comparing the two may make version control easier to explain and understand.

Think of editing your document, or your code, or whatever, as playing a game. Once you've made a lot of progress, you'd like to save. To do so, you click on the "Save" button in your trusty editor.

But this will overwrite the old version. It's like those old school games which only had one save slot: sure you could save, but you could never go back to an older state. Which was a shame, because your previous save might have been right at a really fun part of the game that you'd like to revisit one day.
But this will overwrite the old version. It's like those old school games which only had one save slot: sure you could save, but you could never go back to an older state. Which was a shame, because your previous save might have been right at a really fun part of the game that you'd like to revisit one day. Or worse still, your current save is in an unwinnable state, which means you have to start again.

== Version Control ==

You can "Save As..." a different file, or copy the old one somewhere first before saving if you want to savour old versions. Maybe compress them too to save space. We have just described a primitive labour-intensive form of version control.
When editing, you can "Save As..." a different file, or copy the file somewhere first before saving if you want to savour old versions. Maybe compress them too to save space. This is version control, but very primitive and labour-intensive.

Let's make the problem slightly tougher now. Say you have a bunch of files that go together, such as collection of source code for the same project, or files for a website. Now if you want to keep an old version you have to copy a whole directory of stuff. Keeping many versions around is inconvenient to do by hand.
Let's make the problem slightly tougher now. Say you have a bunch of files that go together, such as collection of source code for the same project, or files for a website. Now if you want to keep an old version you have to archive a whole directory of stuff. Keeping many versions around is inconvenient to do by hand, and gets expensive fast.

In some computer games, saving the game actually writes a directory full of files. They hide these details from the player and present a convenient interface for you to manage saves.

Expand All @@ -29,13 +29,13 @@ How would you set up a system so they can get at each other's saves easily? And

In the old days, every project used centralized version control. A server somewhere held all the saved games. Nobody else did. Every player kept at most a few saved games on their machine. When a player wanted to make progress, they'd download the latest save from the main server, play a while, save and upload back to the server for everyone else to use.

What if a player wanted to get an older saved game for any reason? Maybe the current saved game is in an unfinishable state because somebody forgot to pick up an object back in level three, and they want to find the latest saved game where the game still can completed. Or maybe they want to compare two older saved games to see how much work a particular player did.
What if a player wanted to get an older saved game for some reason? Maybe the current saved game is in an unwinnable state because somebody forgot to pick up an object back in level three, and they want to find the latest saved game where the game can still be completed. Or maybe they want to compare two older saved games to see how much work a particular player did.

There could be many reasons to want to see an older revision, but the outcome is the same. They have to ask the central server for that old save. The more saves they want, the more communication that is required.
There could be many reasons to want to see an older revision, but the outcome is the same. They have to ask the central server for that old saved game. The more saved games they want, the more communication that is required.

The new generation of version control systems, to which Git belong, are known as distributed systems, and can be thought of as a generalization of the centralized systems. When players download from the main server they get every saved game, not just the latest one. It's as if they're mirroring the central server.
The new generation of version control systems, of which Git is a member, are known as distributed systems, and can be thought of as a generalization of centralized systems. When players download from the main server they get every saved game, not just the latest one. It's as if they're mirroring the central server.

One immediately obvious benefit is that when an old save is desired for any reason, communication with the central server is unnecessary.
Thus the initial cloning can be expensive, especially if there's a long history, but it pays off in the long run. One immediately obvious benefit is that when an old save is desired for any reason, communication with the central server is unnecessary.

== Merge Conflicts ==

Expand Down
59 changes: 59 additions & 0 deletions makeover
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# extract table of contents from index.html
BOOKDIR=book
gawk '
/<div class="toc">/ {
print $0
getline #TODO: check this is the <ul> line
print $0
print "<li><a href=\".\">Git Magic</a></li>"
getline
while (!match($0, "</div>")) {
print $0
getline
}
print "</div>"
exit
}
' < $BOOKDIR/index.html > toc.tmp

# for every chapter...
for FILE in $BOOKDIR/*.html
do
if [ $FILE != "$BOOKDIR/index.html" ]
then
# add " - Git Magic" to titles of all pages
sed '/<\/title>/ s/<\/title>/ - Git Magic&/' -i $FILE
# paste ToC into beginning
# and add div section with class content for CSS
sed '/<body/{n; r toc.tmp
a <div class="content">
} ' -i $FILE
sed '/^<\/body/i </div>' -i $FILE
fi
done

# extract shell of index.html
# then insert ToC and preface
gawk '
/<div class="book"/ {
i = 0
for(;;) {
getline
if (match($0, "<div")) i++;
else if (match($0, "</div")) {
i--;
if (i < 0) break;
}
}
sub("</div>","")
}
{ print }
' < $BOOKDIR/index.html | sed '/<body/{n; r toc.tmp
a <div class="content">
r preface.html
a </div>
} ' > tmp.tmp
mv tmp.tmp $BOOKDIR/index.html
rm toc.tmp
11 changes: 11 additions & 0 deletions preface.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Git Magic</h1>
<p>
Git is a version control Swiss army knife. The duct tape of source code management. A reliable versatile multipurpose tool for all your revision control needs.
The tricky part is learning to use it. I'm recording what I've figured out so far in these pages.
</p>
<p>
Rather than explain how it works, I'll provide recipes for particular tasks. After practice, you eventually figure out what's going on behind each trick.
</p>
<p>
<a href="/~blynn/">Ben Lynn</a>
</p>
Loading

0 comments on commit f32ad24

Please sign in to comment.