Inside GitHub with Chris Wanstrath

205
hi

description

"Inside GitHub - A high level overview of the stack and the glue"

Transcript of Inside GitHub with Chris Wanstrath

Page 1: Inside GitHub with Chris Wanstrath

hi

Page 2: Inside GitHub with Chris Wanstrath

Hello.Hi everyone.

Page 3: Inside GitHub with Chris Wanstrath

My name is Chris Wanstrath. I go by @defunkt online.

Page 4: Inside GitHub with Chris Wanstrath

insidegithub

And today I’m going to talk about GitHub.

Page 5: Inside GitHub with Chris Wanstrath

insidegithub

That’s me.

Page 6: Inside GitHub with Chris Wanstrath

GitHub is what we like to call “social coding.”

Page 7: Inside GitHub with Chris Wanstrath

You can see what your friends are doing from your dashboard or news feed

Page 8: Inside GitHub with Chris Wanstrath

Everyone has a profile showing off their code and activity

Page 9: Inside GitHub with Chris Wanstrath

And you can do things like leave comments on commits.

Page 10: Inside GitHub with Chris Wanstrath

But it wasn’t always like this.

Page 11: Inside GitHub with Chris Wanstrath

Originally we just wanted to make a git hosting site.

In fact, that was the first tagline.

Page 12: Inside GitHub with Chris Wanstrath

git repository hosting

git repository hosting.

That’s what we wanted to do: give us and our friends a place to share git repositories.

Page 13: Inside GitHub with Chris Wanstrath

a briefhistory

let’s start with a brief history

Page 14: Inside GitHub with Chris Wanstrath

It’s not easy to setup a git repository. It never was.

But back in 2007 I really wanted to.

Page 15: Inside GitHub with Chris Wanstrath

I had seen Torvalds’ talk on YouTube about git.

But it wasn’t really about git - it was more about distributed version control.

It answered many of my questions and clarified DVCS ideas.

I still wasn’t sold on the whole idea, and I had no idea what it was good for.

Page 16: Inside GitHub with Chris Wanstrath

CVS is stupid

But when Torvalds says “CVS is stupid”

Page 17: Inside GitHub with Chris Wanstrath

and so are you

“and so are you,” the natural reaction for me is...

Page 18: Inside GitHub with Chris Wanstrath

To start learning git.

Page 19: Inside GitHub with Chris Wanstrath

At the time the biggest and best free hosting site was repo.or.cz.

Page 20: Inside GitHub with Chris Wanstrath

Right after I had seen the Torvalds video, the god project was posted up on repo.or.cz

I was interested in the project so I finally got a chance to try it out with some other people.

Page 21: Inside GitHub with Chris Wanstrath

Namely this guy, Tom Preston-Werner.

Seen here in his famous “I put ketchup on my ketchup” shirt.

Page 22: Inside GitHub with Chris Wanstrath

I managed to make a few contributions to god before realizing that repo.or.cz was not different.

git was not different.

Just more of the same - centralized, inflexible code hosting.

Page 23: Inside GitHub with Chris Wanstrath

This is what I always imagined.

No rules. Project belongs to you, not the site. Share, fork, change - do what you want.

Give people tools and get out of their way. Less ceremony.

Page 24: Inside GitHub with Chris Wanstrath

So, we set off to create our own site.

A git hub - learning, code hosting, etc.

Page 25: Inside GitHub with Chris Wanstrath

We started with the code browsing and commit viewing...

Page 26: Inside GitHub with Chris Wanstrath

But once we added the current version of the dashboard, we knew this was different.

Page 27: Inside GitHub with Chris Wanstrath

And eventually “git repository hosting” gave way to “social coding”

Page 28: Inside GitHub with Chris Wanstrath

Join 500,000 coders withover 1,500,000 repositories

Unleash Your Code

What’s special about GitHub is that people use the site in spite of git.

Many git haters use the site because of what it is - more than a place to host git repositories, but a place to share code with others.

Page 29: Inside GitHub with Chris Wanstrath

2007 october

The first commit was on a Friday night in October, around 10pm.

Page 30: Inside GitHub with Chris Wanstrath

2008 january

We launched the beta in January at Steff’s on 2nd street in San Francisco’s SOMA district.

The first non-github user was wycats, and the first non-github project was merb-core.

They wanted to use the site for their refactoring and 0.9 branch.

Page 31: Inside GitHub with Chris Wanstrath

2008 april

A few short months after that we launched to the public.

Page 32: Inside GitHub with Chris Wanstrath

Along the way we managed to pick up Scott Chacon, our VP of R&D

Page 33: Inside GitHub with Chris Wanstrath

Tekkub, our level 80 support druid

Page 34: Inside GitHub with Chris Wanstrath

Melissa Severini, who keeps us all in check

Page 35: Inside GitHub with Chris Wanstrath

Kyle Neath, who makes the site pretty

Page 36: Inside GitHub with Chris Wanstrath

Ryan Tomayko, who helps keep the site running smoothly.

Page 37: Inside GitHub with Chris Wanstrath

Zach Holman, head of enterprise

Page 38: Inside GitHub with Chris Wanstrath

Rick Olson, Rails extraordinaire

Page 39: Inside GitHub with Chris Wanstrath

Eston Bond, Design Generalissimo

Page 40: Inside GitHub with Chris Wanstrath

Corey Donohoe, Director of Shipology

Page 41: Inside GitHub with Chris Wanstrath

And Brian Lopez, our bleeding edge cowboy

Page 42: Inside GitHub with Chris Wanstrath

Oh yeah, and the other founders: PJ and Tom.

Page 43: Inside GitHub with Chris Wanstrath

github.com

That’s where we’re at today.

So let’s talk about the technical details of the website: github.com

Page 44: Inside GitHub with Chris Wanstrath

.com as opposed to fi, which I’m not going to get into today.

You’ll have to invite PJ out if you want to hear about that.

Page 45: Inside GitHub with Chris Wanstrath

We also have a store

Page 46: Inside GitHub with Chris Wanstrath

A job board

Page 47: Inside GitHub with Chris Wanstrath

And do git training

Page 48: Inside GitHub with Chris Wanstrath

the web site

As everyone knows, a web “site” is really a bunch of different components.

Some of them generate and deliver HTML to you, but most of them don’t.

Our site consists of four major code “frameworks” or “apps”

Page 49: Inside GitHub with Chris Wanstrath

rails

1#GitHub.com, Gist, etc

Page 50: Inside GitHub with Chris Wanstrath

resque

2#Background processing, 50ish different job types currently

Page 51: Inside GitHub with Chris Wanstrath

smoke

3#All git calls happen over the wire

Page 52: Inside GitHub with Chris Wanstrath

utils

4#Exception logging, stats, helper apps, etc

Page 53: Inside GitHub with Chris Wanstrath

rails

We use Ruby on Rails 2.2.2 as our web framework.

It’s kept up to date with all the security patches and includes custom patches we’ve addedourselves, as well as patches we’ve cherry-picked from more recent versions of Rails.

Page 54: Inside GitHub with Chris Wanstrath

rails

GitHub is about 20,000 lines of Rails code, not counting Rails itself, plugins, or gems.

Page 55: Inside GitHub with Chris Wanstrath

We found out Rails was moving to GitHub in March 2008, after we had reached out tothem and they had turned us down.

So it was a bit of a surprise.

Page 56: Inside GitHub with Chris Wanstrath

rails plugins

We currently have 27 Rails plugins installed, and that number is always changing.

Page 57: Inside GitHub with Chris Wanstrath

shopify / active_merchant

Page 58: Inside GitHub with Chris Wanstrath

lgn21st / s3_swf_upload

Page 59: Inside GitHub with Chris Wanstrath

technoweenie / serialized_attributes

Page 60: Inside GitHub with Chris Wanstrath

query_trace

Page 61: Inside GitHub with Chris Wanstrath

query_analyzer

Page 62: Inside GitHub with Chris Wanstrath

rubygems

GitHub depends on about 50 RubyGems

Page 63: Inside GitHub with Chris Wanstrath

albino

Page 64: Inside GitHub with Chris Wanstrath

ar-extensions

Page 65: Inside GitHub with Chris Wanstrath

aws-s3

Page 66: Inside GitHub with Chris Wanstrath

faker

Page 67: Inside GitHub with Chris Wanstrath

faraday

Page 68: Inside GitHub with Chris Wanstrath

github-markup

Page 69: Inside GitHub with Chris Wanstrath

rdiscount

Page 70: Inside GitHub with Chris Wanstrath

jekyll

Page 71: Inside GitHub with Chris Wanstrath

gollum

Page 72: Inside GitHub with Chris Wanstrath

redis-rb

Page 73: Inside GitHub with Chris Wanstrath

rack

One of the big features in Rails 2.3 is Rack support.

Page 74: Inside GitHub with Chris Wanstrath

We badly wanted this, but didn’t want to invest the time upgrading.

So using a few open source libraries we’ve wrapped our Rails 2.2.2 instance in Rack.

Page 75: Inside GitHub with Chris Wanstrath

Now we can use awesome Rack middleware like Rack::Bug in GitHub

Page 76: Inside GitHub with Chris Wanstrath

Coders created and submitted dozens of Rack middleware for the Coderack competition last year.

I was a judge so I got the see the submissions already. Some of my favoritewere

Page 77: Inside GitHub with Chris Wanstrath

nerdEd / rack-validate

Page 78: Inside GitHub with Chris Wanstrath

webficient / rack-tidy

Page 79: Inside GitHub with Chris Wanstrath

talison / rack-mobile-detect

sets the X_MOBILE_DEVICE header to the mobile device, if recognized

Page 80: Inside GitHub with Chris Wanstrath

unicorn

We use unicorn as our application server

- master / worker- 16 workers- preforking

Page 81: Inside GitHub with Chris Wanstrath

unicorn

- instant restart after kill- hard 30s request timeouts- control ram growth

Page 82: Inside GitHub with Chris Wanstrath

unicorn

- 0 downtime deploys- protects against bad rails startup- migrations handled old fashioned way

Page 83: Inside GitHub with Chris Wanstrath

nginx

For serving static content and slow clients, we use nginx

nginx is pretty much the greatest http server ever

it’s simple, fast, and has a great module system

Page 84: Inside GitHub with Chris Wanstrath

nginxLimit Zone

Limit simultaneous connections from a client

Page 85: Inside GitHub with Chris Wanstrath

nginxLimit Requests

Limit frequency of connections from a client

Anti-DDOS

Page 86: Inside GitHub with Chris Wanstrath

nginx

I see many people using Rack to do what the Limit modules do.

Don’t.

Page 87: Inside GitHub with Chris Wanstrath

nginxmemcached

memcached support

can serve directly from memcached

Page 88: Inside GitHub with Chris Wanstrath

nginxPush Module

comet!

Page 89: Inside GitHub with Chris Wanstrath

git

The next major part of GitHub is git

Page 90: Inside GitHub with Chris Wanstrath

grit

We wrote an open source library called Gritwhich lets us use git from Ruby

Page 91: Inside GitHub with Chris Wanstrath

mojombo / grit

you can get it here

it originally shelled out to git and just parsed the responses.

which worked well for a long time.

Page 92: Inside GitHub with Chris Wanstrath

gritFile.read()

Eventually we realized, however, that File.read() can be 100 times faster

Page 93: Inside GitHub with Chris Wanstrath

gritsystem()

Than shelling out

Page 94: Inside GitHub with Chris Wanstrath

One of the first things Scott worked on was rewriting the core parts of Gritto be pure Ruby

Basically a Ruby implementation of Git

Page 95: Inside GitHub with Chris Wanstrath

mojombo / grit

And that’s what we run now

Page 96: Inside GitHub with Chris Wanstrath

smoke

Kinda.

Eventually we needed to move of our git repositories off of our web servers

Today our HTTP servers are distinct from our git servers. The two communicate using smoke

Page 97: Inside GitHub with Chris Wanstrath

smoke

“Grit in the cloud”

Instead of reading and writing from the disk, Grit makes Smoke calls

The reading and writing then happens on our file servers

Page 98: Inside GitHub with Chris Wanstrath

bert-rpc

Rather than use Protocol Buffers or Thrift or JSON-RPC, Smoke uses BERT-RPC

Page 99: Inside GitHub with Chris Wanstrath

bert-rpcbert : erlang ::json javascript:

BERT is an erlang-based protocol

BERT-RPC is really great at dealing with large binariesWhich is a lot of what we do

Page 100: Inside GitHub with Chris Wanstrath

bert-rpc

we have four file servers, each running bert-rpc servers

our front ends and job queue make RPC calls to the backend servers

Page 101: Inside GitHub with Chris Wanstrath

mojombo / bertrpc

You can grab bert-rpc on GitHub

Page 102: Inside GitHub with Chris Wanstrath

mojombo / bert

Or if you just want to play with BERT

Page 103: Inside GitHub with Chris Wanstrath

chimney

We have a proprietary library called chimney

It routes the smoke. I know, don’t blame me.

Page 104: Inside GitHub with Chris Wanstrath

chimney

All user routes are kept in Redis

Chimney is how our BERT-RPC clients know which server to hit

It falls back to a local cache and auto-detection if Redis is down

Page 105: Inside GitHub with Chris Wanstrath

chimney

It can also be told a backend is down.

Optimized for connection refused but in reality that wasn’t the real problem - timeouts were

Page 106: Inside GitHub with Chris Wanstrath

proxymachine

All anonymous git clones hit the front end machines

the git-daemon connects to proxymachine, which uses chimney to proxy yourconnection between the front end machine and the back end machine (which holdsthe actual git repository)

very fast, transparent to you

Page 107: Inside GitHub with Chris Wanstrath

mojombo / proxymachine

proxymachine can be used to proxy any kind of tcp connection

open source

Page 108: Inside GitHub with Chris Wanstrath

ssh

Sometimes you need to access a repository over ssh

In those instances, you ssh to an fe and we tunnel your connection tothe appropriate backend

To figure that out we use chimney

Page 109: Inside GitHub with Chris Wanstrath

node.js

Page 110: Inside GitHub with Chris Wanstrath

node.jsdownloads

Page 111: Inside GitHub with Chris Wanstrath

node.jsdownloadshttp => https <img>

Page 112: Inside GitHub with Chris Wanstrath

node.jsdownloadshttp => https <img>event streams

Page 113: Inside GitHub with Chris Wanstrath

hubot

Page 114: Inside GitHub with Chris Wanstrath

jobs

We do a lot of work in the background at GitHub

Page 115: Inside GitHub with Chris Wanstrath

resque

Currently we use a system called Resque.

Page 116: Inside GitHub with Chris Wanstrath

defunkt / resque

You can grab it on GitHub

Page 117: Inside GitHub with Chris Wanstrath

resque

- dealing with pushes- web hooks- creating events in the database- generating GitHub Pages- clearing & warmingcaches- search indexing

Page 118: Inside GitHub with Chris Wanstrath

queues

In Resque, a queue is used as both a priority and a localization technique

By localization I mean, “where your workers live”

Page 119: Inside GitHub with Chris Wanstrath

queuescritical,high,low

these three run on our front end servers

Resque processes them in this order

Page 120: Inside GitHub with Chris Wanstrath

queuespage

GitHub Pages are generated on their own machine using the `page` queue

Page 121: Inside GitHub with Chris Wanstrath

queuesarchive

And tarball and zip downloads are created on the fly using the `archive` queue on our archiving machines

Page 122: Inside GitHub with Chris Wanstrath

search

On GitHub, you can search code, repositories, and people

Page 123: Inside GitHub with Chris Wanstrath

solr

Solr is basically an HTTP interface on top of Lucene. This makes it pretty simpleto use in your code.

We use solr because of its ability to incrementally add documents toan index.

Page 124: Inside GitHub with Chris Wanstrath

Here I am searching for my name in source code

Page 125: Inside GitHub with Chris Wanstrath

solr

We’ve had some problems making it stable but luckily the guys at Pivotalhave given us some tips

Like bumping the Java heap size.

Whatever that means

Page 126: Inside GitHub with Chris Wanstrath

database

Our database story is pretty uninteresting

Page 127: Inside GitHub with Chris Wanstrath

mysql

We use mysql 5

Page 128: Inside GitHub with Chris Wanstrath

master / slave

All reads and writes go to the master

We use the slave for backups and failover

Page 129: Inside GitHub with Chris Wanstrath

caching

On the site we do a ton of caching using memcached

Page 130: Inside GitHub with Chris Wanstrath

fragments

We cache chunks of HTML all over

Usually they are invalidated by some action

Page 131: Inside GitHub with Chris Wanstrath

fragments

Formerly we invalidated most of our fragments using a generation scheme,where you put a number into a bunch of related keys and increment itwhen you want all those caches to be missed (thus creating new cache entries with fresh data)

Page 132: Inside GitHub with Chris Wanstrath

fragments

But we had high cache eviction due to low ram and hardware constraints, and foundthat scheme did more harm than good.

We also noticed some cached data we wanted to remain forever was being evicted due to the slabs with generational keys filling up fast

Page 133: Inside GitHub with Chris Wanstrath

page

We cache entire pages using nginx’s memcached module

Lots of HTML, but also other data which gets hit a lot and changes rarely:

Page 134: Inside GitHub with Chris Wanstrath

page

- network graph json- participation graph data

Always looking to stick more into page caches

Page 135: Inside GitHub with Chris Wanstrath

object

We do basic object caching of ActiveRecord objects such as repositories and users all over the place

Caches are invalidated whenever the objects are saved

Page 136: Inside GitHub with Chris Wanstrath

associations

We also cache associations as arrays of IDs

Grab the array, then do a get_multi on its contents to get a list of objects

That way we don’t have to worry about caching stale objects

Page 137: Inside GitHub with Chris Wanstrath

walker

We also have a proprietary caching library called Walker

Page 138: Inside GitHub with Chris Wanstrath

walker

It originally walked trees and cached them when someone pushed

But now it caches everything related to git:

Page 139: Inside GitHub with Chris Wanstrath

walker

- commits- diffs- commit listing- branches- tags- everything

Page 140: Inside GitHub with Chris Wanstrath

Every git-related page load hits Walker a lot

Page 141: Inside GitHub with Chris Wanstrath

walker

For most big apps, you need to write a caching layerthat knows your business domain

Generic, catch-all caching libraries probably won’t do

Page 142: Inside GitHub with Chris Wanstrath

events

An example of this is our events system

Page 143: Inside GitHub with Chris Wanstrath
Page 144: Inside GitHub with Chris Wanstrath

This is one fragment

Page 145: Inside GitHub with Chris Wanstrath

Each of these is a fragment

Page 146: Inside GitHub with Chris Wanstrath

They’re also cached as objects

Page 147: Inside GitHub with Chris Wanstrath

As well as a list of ids

Page 148: Inside GitHub with Chris Wanstrath

And that’s just for the dashboard...

Page 149: Inside GitHub with Chris Wanstrath

optimizations

So what other optimizations have we done

Page 150: Inside GitHub with Chris Wanstrath

asset servers

Well we do the common trick of serving assets from multiple subdomains

Page 151: Inside GitHub with Chris Wanstrath

asset serversassets0.github.comassets1.github.com

and so forth

Page 152: Inside GitHub with Chris Wanstrath

sha asset id

Instead of using timestamps for asset ids, which may end up hitting the diskmultiple times on each request, we set the asset id to be the sha of the last commitwhich modified a javascript or css file

Page 153: Inside GitHub with Chris Wanstrath

sha asset id/css/bundle.css?197d742e9fdec3f7

/js/bundle.js?197d742e9fdec3f7

Now simple code changes won’t force everyone to re-download the css or js bundles

Page 154: Inside GitHub with Chris Wanstrath

bundling

For bundling itself, we use

Page 155: Inside GitHub with Chris Wanstrath

bundling

yui’s compressor for css and

Page 156: Inside GitHub with Chris Wanstrath

bundling

google’s closure compiler for javascript

we don’t use the most aggressive setting because it means changingyour javascript to appease the compression gods, which we haven’t committed to yet

Page 157: Inside GitHub with Chris Wanstrath

scripty 301

Again, for most of these tricks you need to really pay attention to your app.

One example is scriptaculous’ wiki

Page 158: Inside GitHub with Chris Wanstrath

scripty 301

When we changed our wiki URL structure, we setup dynamic 301 redirects for the old urls.

Scriptaculous’ old wiki was getting hit so much we put the redirect into nginx itself -this took strain off our web app and made the redirects happen almost instantly

Page 159: Inside GitHub with Chris Wanstrath

ajax loading

We also load data in via ajax in many places.

Sometimes a piece of information will just take too long to retrieve

In those instances, we usually load it in with ajax

Page 160: Inside GitHub with Chris Wanstrath
Page 161: Inside GitHub with Chris Wanstrath
Page 162: Inside GitHub with Chris Wanstrath

If Walker sees that it doesn’t have all the information it needs, it kicks off a jobto stick that information in memcached.

Page 163: Inside GitHub with Chris Wanstrath

We then periodically hit a URL which checks if the information is in memcached or not. If it is, we get it and rewrite the page with the new information.

Page 164: Inside GitHub with Chris Wanstrath

We use this same trick on the Network Graph

Page 165: Inside GitHub with Chris Wanstrath

Fork Queue

Page 166: Inside GitHub with Chris Wanstrath

ajax loading

and anywhere else it makes sense.

Page 167: Inside GitHub with Chris Wanstrath

comet loading

very soon this will all be comet, though

Page 168: Inside GitHub with Chris Wanstrath

monitoring

what do we use for monitoring?

Page 169: Inside GitHub with Chris Wanstrath

nagios

Our support team monitors the health of our machines and coreservices using nagios.

I don’t really touch the thing.

Page 170: Inside GitHub with Chris Wanstrath

Here’s a screenshot from my IE browser, complete with the ICQ plugin

Page 171: Inside GitHub with Chris Wanstrath

resque web

We monitor our queue using Resque’s included Sinatra app

Page 172: Inside GitHub with Chris Wanstrath
Page 173: Inside GitHub with Chris Wanstrath

haystack

We use an in-house app called Haystack to monitor arbitrary information,tracked as JSON.

Page 174: Inside GitHub with Chris Wanstrath

Here’s an example of Haystack’s “exceptions” view

Page 175: Inside GitHub with Chris Wanstrath

collectd

We also use collectd to monitor load, RAM usage, CPU usage, and otherapp-related metrics

Page 176: Inside GitHub with Chris Wanstrath

pingdom

pingdom sends us SMSes when the site is down

it’s nice

Page 177: Inside GitHub with Chris Wanstrath

tender

tender is what we use for customer support

Page 178: Inside GitHub with Chris Wanstrath

it works incredibly well, and they’re constantly improving it

Page 179: Inside GitHub with Chris Wanstrath

testing

Our testing setup is pretty standard

Page 180: Inside GitHub with Chris Wanstrath

test unit

We mostly use Ruby’s test/unit.

We’ve experimented with other libraries including test/spec, shoulda, and RSpec, but in the endwe keep coming back to test/unit

Page 181: Inside GitHub with Chris Wanstrath

git fixtures

As many of our fixtures are git repositories, we specify in the test what sha we expect to be the HEAD of that fixture.

This means we can completely delete a git repository in one test, then have it back inpristine state in another. We plan to move all our fixtures to a similar git-system in the future.

Page 182: Inside GitHub with Chris Wanstrath

machinist

We use machinist for our fixtures

Page 183: Inside GitHub with Chris Wanstrath

notahat / machinist

Page 184: Inside GitHub with Chris Wanstrath

running_man

Gives us setup_once

Use it to cache machinist fixtures on a per-test-class basis

Page 185: Inside GitHub with Chris Wanstrath

technoweenie / running_man

Page 186: Inside GitHub with Chris Wanstrath

ci joe

We use ci joe, a continuous integration server, to run on tests after each push.

He then notifies us if the tests fail.

Page 187: Inside GitHub with Chris Wanstrath
Page 188: Inside GitHub with Chris Wanstrath
Page 189: Inside GitHub with Chris Wanstrath

defunkt / cijoe

You can grab him at github

Page 190: Inside GitHub with Chris Wanstrath

staging

We also always deploy the current branch to staging

This means you can be working on your branch, someone else can be working on theirs,and you don’t need to worry about reconciling the two to test out a feature

One of the best parts of Git

Page 191: Inside GitHub with Chris Wanstrath

security

Page 192: Inside GitHub with Chris Wanstrath

github.com/security

having a security page really helps

Page 193: Inside GitHub with Chris Wanstrath

[email protected]

we get weekly emails to our security email (that people find on the security page)

and people are always grateful when we can reassure them or a answer their question

Page 194: Inside GitHub with Chris Wanstrath

regular audits

if you can, find a security consultant to poke your site for XSS vulnerabilities

having your target audience be developers helps, too

Page 195: Inside GitHub with Chris Wanstrath

24/7 monitoring

24/7 monitoring is cool too

Page 196: Inside GitHub with Chris Wanstrath

backups

backups are incredibly important

don’t just make backups: ensure you can restore them, as well

Page 197: Inside GitHub with Chris Wanstrath

sql

we keep nightly, off-site backups of our sql databases

Page 198: Inside GitHub with Chris Wanstrath

git

and the same for all our git repositories

Page 199: Inside GitHub with Chris Wanstrath

the future

Page 200: Inside GitHub with Chris Wanstrath

svn

Page 201: Inside GitHub with Chris Wanstrath

pull requests

Page 202: Inside GitHub with Chris Wanstrath

organizations

Page 203: Inside GitHub with Chris Wanstrath

...and more

Page 204: Inside GitHub with Chris Wanstrath

Questions?thanks for coming

Page 205: Inside GitHub with Chris Wanstrath

Thanks.thanks for coming