Release Early, Release Often for Mobile Games

February 12th, 2011 No comments

As I’m closing in on the launch of my first game, I’ve come across a million things that I wish I had more time to work on. My grand vision when I started this thing has turned into a race to the finish where I drop everything non-essential so I can get it out the door. Recently I’d been feeling discouraged, so I took a few moments to stop and get some perspective.

In everything I’ve learned about building web applications, “Release Early, Release Often” is the mantra. It’s definitely better to get things out in front of your customers early so you can see how they want to use it and pivot. It’s also easier to manage a release cycle that’s a few days (or hours) long, rather than a six month project. For apps, especially those in hit-driven fields like games, this seems to make a little less sense. It’s not like you can put out a half-baked first level and hope your customers will keep it around long enough to update when you get around to putting out level two or fixing your terrible control scheme. These types of apps typically only have one shot of attracting a user. The part I forgot about is that in a hit-driven field, you’re banking on the fact that you’re going to be releasing frequently. You’re also relying on reusing technology, process, or marketing improvements that were factored into your current project.

If you go look through a timeline of releases from some of the top iOS game companies out there, their first games weren’t 3D immersive techfests. Some of them weren’t even all that fun! The key is that their next titles were usually more complex and better made. It’s OK to put out a product that doesn’t live up to your expectations, so long as you incorporate as much as possible into your next project.

Categories: Main Tags:

Hiring a Lawyer for your Startup

January 28th, 2011 No comments

I recently switched my hours to part-time at my job to dedicate more time to the mobile game company I’ve started on the side. In doing this, I wanted to make sure the intellectual property I was creating for my games company would belong to me and wouldn’t get tied up in the IP agreement I’d signed with my employer when I started. I needed a lawyer. Having little experience working with attorneys before, I had no idea about the right way to go about finding somebody who could help my business succeed while not also bankrupting me. Here are a few things I’ve learned from going through the process.

The first thing to do is to get a list of possibilities together. I leveraged my personal contacts as much as possible, asking them for recommendations. If you’re on (or know people on) email lists of local entrepreneurs, that’s a great place to ask for suggestions. Hacker News can be a great resource also. Once I got the list together, I narrowed it down to 6-8 that were highly recommended and seemed to be in line with what I was looking for.

Every lawyer will give you an initial consultation to figure out more about your business and sell you on their abilities. This is a great time to talk about what you’re trying to do, as well as specific issues to try to get their opinions. Since you’re not paying for this, you might as well get as much advice as possible! They’re not going to draft anything for you, but if you’ve got conceptual questions, this is a great time to get them answered.

You also want to get some basic information about the lawyer you’ll be working with and their payment practices. Questions to ask during the consultation:

How much of your time is spent on emerging businesses or startups? - Legal recommendations are very different for small businesses versus the Fortune 500. There are so many lawyers out there focusing on startups that there’s very little reason anymore to work with someone who isn’t.

How much of your time is spent on technology businesses? – Someone who knows your subject area will know common practices and be able to give you better advice than someone for whom you have to explain basics. For example, there are ways to structure an apps business that make it easier to sell one of your apps to another company. Someone with experience will know when this is a good idea and be able to proactively suggest this. As above, there are so many attorneys specializing in working with technology companies that you might as well find someone who knows your business.

Are you full service? – Some law firms are “full service”, meaning they have departments specializing in most issues you’ll come across, like intellectual property, M&A, and litigation. That can be helpful, but usually comes at a price. Many startups can do fine (and save money!) with a smaller law firm. Many full service firms have offices in all the major markets, like New York, DC, and Silicon Valley, which can be helpful if you’re thinking about moving to or raising money in another city.

Are you the partner/associate that’s going to be doing my work? – At big law firms, many times the partner you talk to sells clients on the firm and handles high level details, but for day-to-day stuff you’ll be dealing with an associate. If this is the case, make sure you also talk to the associate. They’re going to have a lot bigger impact on your relationship than the partner. If you’re dealing with a one-person or boutique law firm, odds are good you’re talking to the person you’ll be working with, but it’s always good to check.

How much is your hourly rate? – Every lawyer is going to spin this differently, but there is definitely a case to be made for the rate vs efficiency argument. If you’ve got an inexperienced lawyer who’s going to have to do a bunch of research, they might charge you two hours for something that would take an experienced lawyer 15 minutes. This can add up quickly! If rate is a primary concern, a good balance can be found in somebody who worked at a big firm for years, then started their own practice. They’ll have lots of experience, but lower rates.

Is there a retainer required? – If you don’t have a lot of work to be done, putting down $5000 for a retainer makes no sense and can be a real drain on your finances. In many cases, you can work out an agreement where the firm will do work without a retainer as long as there aren’t an unreasonable amount of hours unpaid. When I was first starting, the initial work ended up getting completed in 2-3 hours, so I wasn’t a big payment risk. Obviously if you need hundreds of hours of work, they may evaluate the risk a little differently. This is usually negotiable and if they want your business, they’ll find a way to make it work. If you’re just starting out and don’t have a lot of legal needs, paying a large upfront retainer or a monthly retainer makes no sense.

Do you mainly work with clients who’re raising money? – Some of the big firm lawyers can help you raise VC or angel money through introductions to contacts. In many cases, they’ll float you the incorporation and setup fees in exchange for getting paid when you raise money, since closing a round generates a boatload of legal fees. This can be very helpful if you’re trying to raise money, but result in unwanted pressure if you aren’t. I was starting a lifestyle business, so raising money wasn’t a goal. One of the guys I talked to told me they mainly dealt with people who’re trying to get to a liquidation event, and most of their clients raised money. In that case my interests weren’t aligned with theirs, so we both agreed that working together wasn’t the best idea.

How much will it cost to incorporate my business? – If you’ve already incorporated, ignore this section. I was surprised at the variety of rates I heard for this service. If all you need is a standard business set up, it should be fairly affordable. Most lawyers I spoke to were in the $500-$800 range. Obviously if you have a lot of custom work required, it’s going to cost a lot more, but there’s no way you should be paying $5000 just for a fill-in-the-blanks operating agreement and incorporation papers.

Once you’ve met with everybody on your list, you should be in good position to decide. I’m no expert on the legal realm, so let me know if there are other issues I missed here.

You can discuss this on Hacker News.

Categories: Main Tags: ,

Goals for 2011

January 3rd, 2011 No comments

I’ve been reading through Seth Godin’s Linchpin recently and of the main themes, one has been sticking out to me: shipping. Especially at the end of the year, you want to be able to look back and say “What have I accomplished?” I wish I could write a year-end post like his, describing the many things he completed and shipped in 2010. I’ve spent the last few weeks figuring out my major goals and steps I can take towards accomplishing them in 2011.

First and foremost, I want to start a product company. I’ve worked at two very different startups and enjoyed the challenges at both. I also feel that given my technology background and entrepreneurial knowledge, starting a company is the best chance I have for breakout success. I’m working on mobile games now, but feel that’s more of a hobby project. I don’t have enough of a passion for games to see myself still spinning out a few games a year 7-8 years from now. My opinion could change depending on how much success I have, but for the moment the games business is not my long-term focus.

In conjunction with starting a company, I’m interested in pursuing YCombinator or TechStars in 2012. They both sound amazing, could teach me a lot, and would have a huge impact on whatever business I start. They’re both also insanely competitive, so coming up with ideas, shipping products, and demonstrating that I can get things done this year would go a long ways. Between living arrangements, training for Ironman, and lack of preparation, I’m not going to be able to apply for 2011, but I think I could make a strong case for winter or summer 2012. Pinning all my hopes on a program that competitive would be foolish, but everything I’d need to do to prepare for a tech startup program would be beneficial if I decided to start a company on my own, so I think all of these goals are 100% worth it.

Given the big picture goals listed above, I came up with a few goals for 2011 that will put my in good position to achieve my long-term goals. I’m going to be tracking progress on these weekly to make sure I’m not falling behind on anything.

Launch three games – I think this is an attainable number that would teach me a lot, demonstrate that I can ship, and hopefully make some money.
Launch one non-game product or app – Creating and launching games is very different from any other type of tech product, so I’d like to put something else out there. It doesn’t necessarily have to be a big idea, but I’d like to get something substantial that takes a different type of thinking and marketing than casual games.
Come up with solid business ideas – In order to start a business or apply to the major tech startup programs, I need a real idea. They all say that the idea isn’t as important as the person, but it’s the idea that starts the conversation, so I might as well not have to overcome a terrible idea. I’m going to schedule dedicated time every week for industry research and brainstorming so this doesn’t get neglected. By the end of the year, I want at least one well thought out idea that I’d feel comfortable starting and working into a substantial business.
Read and complete all exercises from SICP – I feel like ever since I finished my math degree, I haven’t been pushing my brain as much as I used to. Once you learn a language enough to be productive, there isn’t much that pushes you mentally in day-to-day development. In 2011, I’m going to start every day off with mental exercise. Structure and Interpretation of Computer Programs gets recommended all the time and seems like a good place to start. Others have tried and completed this in a year, so I think it’s a reasonable goal.
Finish an Ironman triathlon – My girlfriend got me into this hobby last year and I really enjoy it. It’s good to have a completely non-technical goal to work toward so I can balance out my life and not sit in front of the computer all day. Completing an Ironman will be a huge accomplishment, it’ll get me in shape, and I’m sure it’ll be fun too.
Build better online presence – I feel like I’m smarter and work harder than my online presence or resume makes me look, so in 2011 I’m going to fix that. Many of my other goals will work toward this, like shipping four products, but highlighting my achievements, getting more content into my blog, and a better presence on some key sites will help a lot in convincing people that I’m serious. Specifically, I’m going to reorganize this site to highlight things I’ve shipped so people looking me up on Google figure out quickly that I get things done. I’m going to average one blog post per week throughout the year. I’m also going to try to get recommendations on LinkedIn, and keep a more active presence in some of the relevant online/Meetup communities.

That’s it for my 2011 goals. Stay tuned for more posts and updates on progress. Happy New Year!

Categories: Main Tags:

Game Engine Design / iPhone Game Engine Resources

January 18th, 2010 No comments

I’m in the process of writing a simple game engine for the iPhone and have been doing a lot of research about game engine design. I also looked into using a prebuilt iPhone game engine, but decided I’m more interested in writing it myself (because of technical, business, and hacker ego reasons). Here are some resources I found helpful.

Books
Game Engine Architecture – A textbook about game engine design, this presents options and tradeoffs for each piece of the engine. Light on actual coding, so you’ll have to be able to develop things yourself, but jam-packed with useful information. I found this invaluable while in the design stage.
Game Coding Complete – Walks through the process of building a game engine and using it to create a full-fledged game, complete with AI and multiplayer networking. Found it useful in tying the pieces together, but only presents one approach to most problems.

Presentations
Gamasutra has all the presentations from the Game Developers Conference from 2000-2003 (Use the links in the sidebar to navigate year).
Marcin Chady – Theory and Practice of Game Object Component Architecture – The best presentation I found about component driven game object design.
Alex Duran – Building Object Systems – Features, Tradeoffs, and Pitfalls
Scott Bilas – A Data-Driven Game Object System
Rob Fermier – Creating a Data Driven Engine: Case Study: The Age Of Mythology
Doug Church – Object Systems
Mick West – Refactoring Game Entities with Components
Kyle Wilson has a blog with a bunch of strong posts about engine design. Be sure to check out the old posts as well.

iPhone Engines
Unity 3D – Commercial 3D engine. Combines powerful scripting with a visual editor to dramatically speed up the development process. Hundreds of games on the App Store. Well laid out component model.
Oolong Engine – Open source 3D engine. Uses PowerVR POD for storing meshes and Bullet physics.
SIO2 – Open source 3D engine. Toolchain built around Blender and integrates with Bullet physics.
Cocos 2D – Open source 2D engine. Well organized.
Torque 2D – Commercial 2D engine
Torque 3D – Commercial 3D engine
Shiva 3D – Commercial 3D engine. Windows only editor, but supports iPhone publishing

Engines for other platforms
Unreal – One of the most successful game engines on the market. Worth reading through the documentation to pick up on design considerations. Separates out most game logic into a custom scripting language called UnrealScript.
Source – Valve’s engine for Half Life 2 and many mods. Extensive wiki documentation.
idTech 3 – Engine from Quake III Arena, now open sourced. A few years out of date, but shows a lot about client-server programming as well as insane performance optimizations. There are a couple people who have gone through the source and give pointers on things to look at, which is immensely helpful .
Panda3D – Open source engine written in Python and C++. All game logic is written in Python. Does a good job of showing how to separate engine code from script.
OGRE – Open source C++ engine in process of being ported to iPhone
Crystal Space – C++ open source engine

Categories: Game Engine, iPhone Tags: , ,

Startup Engineers: Learning the Core

January 3rd, 2010 1 comment

At any new job, there are a lot of things for engineers to learn. It’s easy to get distracted by platforms, languages, team characteristics, the industry, business models, etc. One area that gets frequently overlooked is learning your company’s core competency or technology. At every company (or department within a large company), there’s an area that’s their specialty. For Apple, it’s building intuitive products. For Oracle, it’s organizing huge amounts of data. While you can come out of a job and say that you grew your general software development skills, it’s better to do that and gain a new area of expertise.

Your company’s core strength may not be part of your job description. You may be working on back-end enterprise reporting for a company that prides itself on brilliant user interfaces or doing interface work for a company that specializes in data analysis. While you may not ever be directly working on the core competency, it’s still possible to learn enough to be useful later on. If it’s something that can be researched on your own, grab some books and do some reading. Talk to people who are working on it and get their opinions and ideas. Unless your company is highly secretive, you probably have source code access. Look into what tools are being used and read the source. You don’t necessary need to know it line by line, just enough that you understand the concepts involved and could participate in a discussion about pros and cons.

Obviously, if you’re working on web applications you should be very familiar with web programming. It’s going to be assumed in the future that you’re an expert in the language and platform on which you spent the most time. While it’s essential to learn these things, most companies’ core competency is not knowledge of a platform or language. 37signals aren’t focused on Ruby on Rails, they design simple, clean products. ngmoco don’t pride themselves on knowing iPhone APIs better than anyone else, they’re good at making fun mobile games. While learning the platform is essential, it’s important not to confuse that with learning the company’s core competency.

Being familiar with your company’s core competency enables you to be part of the important discussions that go on every day. When you don’t understand the key concepts involved, you’ll have a hard time participating in conversations about changing the core product. When you have the knowledge and can offer suggestions, you’ll get involved more and will be seen as more valuable to the company. If a key project needs another person, you’ll be much more likely to get on it. A developer with key domain knowledge is also much more difficult to replace, which can benefit you financially and in terms of job security.

Unless you’re staying focused to one specific industry, these things are usually fairly unique. In the first two jobs I’ve had out of college, I’ve learned all about call platforms (the software that manages automated phone calls), machine learning, and ad servers. While some of these are more generally applicable than others, I’ve had all of them come up in conversations about unrelated topics. When you’re applying for your next job, every other applicant is also going to list being good at web programming. It’s the other interesting details that make your resume really stand out.

Categories: Main Tags: , ,

For Startup Employees, Learning is Job One

November 22nd, 2009 No comments

Earlier this month, Mark Suster published what I consider to be one of the best startup blog posts of the year in his Earn or Learn article. The first point in the article refreshed something that young, mid-stage startup employees (like myself) frequently forget: your engineer’s share of the options isn’t going to make you rich. It may be a nice bonus, but there’s almost no chance of retiring in the unlikely event of a liquidation.

The second point resonated even stronger. If the job you’re in isn’t going to make you rich, it needs to be preparing you for the position that will. If you’re in a learning stage, keep that in mind every day on your way to work. Since the article was talking about advice for whether or not to take a new job it also left out one possibility: move. If you’re holding a job with little possibility of earning or learning, it may be time for a change.

My next few posts will give some areas of concentration for startup employees trying to learn as much as possible from their experience.

Categories: Main Tags: , ,

Wireshark ChmodBPF errors on Snow Leopard

October 3rd, 2009 32 comments

When I got Snow Leopard, I decided to do some house cleaning. I wiped the disk and reinstalled everything from scratch. I didn’t have any problems along the way until I went to install my favorite network protocol analyzer: Wireshark.

Installing is a simple matter of dragging the application into your Applications folder, but there’s also a startup item that sets some necessary permissions. To set that up, go into the Utilities folder on the Wireshark disk image, and drag the ChmodBPF folder onto the StartupItems shortcut. It’ll prompt you to authenticate and then copy. If you restart at this point, you’ll get an error message that says “Insecure Startup Item disabled. – “/Library/StartupItems/ChmodBPF” has not been started because it does not have the proper security settings.”

Using information from an Apple support article, I realized you need to change the owner of the scripts for them to be run on startup. Run the command below and everything will work fine!

cd /Library/StartupItems
sudo chown -R root:wheel ChmodBPF


Update (7/14/2010)
– Make sure you restart your computer after running this command. The script only runs at startup, so just changing the permissions doesn’t do anything by itself. You have to restart for the script to run.

Update (1/26/2011) – From whaefelinger (in the comments): No you don’t need to [restart your computer]. To check whether the script gets automatically executed, just log out and log in again. Strictly talking, you don’t even need to do that. Just run the script like ‘sudo /Library/StartupItems/ChmodBPF/ChmodBPF start’ to get going.

Categories: Misc Tags:

Git Workflow – Part 4: Remote Branches

October 3rd, 2009 No comments

The final piece of Git I’ll be covering is using shared remote branches. This can be helpful if you have a team working on a development and a release branch, among other scenarios.

I’ll start by setting up a central repository and two working repositories based off it. I’ll be supplying an extra argument to the clone command to make things less confusing, this gives the name of the directory in which to check out the branch. For example, “git checkout first.git” (no argument) checks out into a directory called “first”. Using “git checkout first.git second” will check out into a directory called “second”.

Kleinschs-Macbook:tmp nick$ mkdir first.git && cd first.git
Kleinschs-Macbook:first.git nick$ git --bare init --shared
Initialized empty shared Git repository in /Users/nick/tmp/first.git/
Kleinschs-Macbook:first.git nick$ cd ..
Kleinschs-Macbook:tmp nick$ git clone first.git second
Initialized empty Git repository in /Users/nick/tmp/second/.git/
warning: You appear to have cloned an empty repository.
Kleinschs-Macbook:tmp nick$ cd second
Kleinschs-Macbook:second nick$ echo 'First file contents' > file1
Kleinschs-Macbook:second nick$ git add file1
Kleinschs-Macbook:second nick$ git commit -am'added first file'
[master (root-commit) 19b39e3] added first file
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1
Kleinschs-Macbook:second nick$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 243 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/nick/tmp/first.git
 * [new branch]      master -> master
Kleinschs-Macbook:second nick$ cd ..
Kleinschs-Macbook:tmp nick$ git clone first.git third
Initialized empty Git repository in /Users/nick/tmp/third/.git/

Now that I have two working repositories, I’ll go create a release branch on the second repository.

Kleinschs-Macbook:tmp nick$ cd second
Kleinschs-Macbook:second nick$ git checkout -b release
Switched to a new branch 'release'
Kleinschs-Macbook:second nick$ echo 'Second file contents' > file2
Kleinschs-Macbook:second nick$ git add file2
Kleinschs-Macbook:second nick$ git commit -am'added file2'
[release 48a00ee] added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

Since I have this release branch, I’d like to expose it to the rest of the team so that everyone is looking at the same version. Adding a branch is as simple as doing a push with the name of the new branch. In this example, I’m telling Git to push to a remote branch that doesn’t exist, so it creates it.

Kleinschs-Macbook:second nick$ git push origin release:release
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 292 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/nick/tmp/first.git
 * [new branch]      release -> release

Listing the branches will show that the branch was created on the remote repository as well.

Kleinschs-Macbook:second nick$ git branch -a
  master
* release
  remotes/origin/master
  remotes/origin/release

Now let’s go over to the third repository and make sure we can access the release branch. First we do a pull to make sure we have the latest data from the remote server.

Kleinschs-Macbook:second nick$ cd ../third/
Kleinschs-Macbook:third nick$ git pull
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/nick/tmp/first
 * [new branch]      release    -> origin/release
Already up-to-date.
Kleinschs-Macbook:third nick$ ls
file1

We’re still not seeing the second file that was checked in on the release branch. This is because we’re still on the master branch at this point. In order to access the remote release branch, we need to create a local tracking branch for our changes. A tracking branch is a local branch that’s set up with a remote branch so that pushes and pulls go to the corresponding remote branch. In order to set up a tracking branch, just supply the “–track” flag to the branch command.

Kleinschs-Macbook:third nick$ git branch --track release origin/release
Branch release set up to track remote branch release from origin.
Kleinschs-Macbook:third nick$ git checkout release
Switched to branch 'release'
Kleinschs-Macbook:third nick$ ls
file1	file2

As you can see, we received the second file that was checked in on the release branch, so we should be ready to go. There’s one more thing I’d like to clear up. What if you have an existing branch that you’d like to have track a remote branch? The easiest way to do this is to edit your Git config file. Outputting the config from the the third repository will make this a little more clear.

Kleinschs-Macbook:third nick$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
[remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*
	url = /Users/nick/tmp/first.git
[branch "master"]
	remote = origin
	merge = refs/heads/master
[branch "release"]
	remote = origin
	merge = refs/heads/release

The section for branch “release” has the relevant information. If you wanted to set up the second repository so its release branch was tracking the remote release branch, you just need to add these three lines to second/.git/config.

This concludes my series on Git. There’s a lot more to it than these four articles describe, but this should be a good jumping off point.

Categories: How-To Tags:

Git Workflow – Part 3: Remote Operations

September 30th, 2009 3 comments

Using Git on a single machine may have its uses, but most people using Git are using it for its remote operations. Git functions in a variety of ways, I’ll be focusing on a central repository in this article. For more complicated workflows, see the Git Book.

The first thing to do is to set up a central repository. You can make it a normal Git repository like any other, but a few things will be easier if you make it what’s called a bare repository. This means that there’s no working copy, it just stores revisions. Adding the flag “–bare” to the init command sets it up as bare. I also like to add the “–shared” flag if you’re going to be sharing it across multiple users, this helps fix permissions. Look it up if you’re very curious. It also helps to name the shared repository ending in “.git”. If it’s set up that way, when people clone it, Git will lose the extension and just take the name. We’ll see that below.

Kleinschs-Macbook:tmp nick$ mkdir first.git && cd first.git
Kleinschs-Macbook:first.git nick$ git --bare init --shared
Initialized empty shared Git repository in /Users/nick/tmp/first.git/

Now that the bare repository is set up, we need to get something into it. There are two ways to connect to a remote repository: cloning and adding to an existing repository. I’ll add it to an existing repository first. This can be handy if you want to import existing files into a new repository.

Kleinschs-Macbook:first.git nick$ cd ..
Kleinschs-Macbook:tmp nick$ mkdir second.git && cd second.git
Kleinschs-Macbook:second.git nick$ git init
Initialized empty Git repository in /Users/nick/tmp/second.git/.git/
Kleinschs-Macbook:second.git nick$ echo 'First file contents' > file1
Kleinschs-Macbook:second.git nick$ git add file1
Kleinschs-Macbook:second.git nick$ git commit -am'Added file1'
[master (root-commit) 1a603a8] Added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

Up to this point everything is standard. In order to commit changes into the central repository, we need to add the server and push the changes. The “remote” command takes care of remote repository setup in Git. The “remote add” adds a remote location, with the first parameter being the name and second being the location. In this example I’m using a local repository, but you could also do it via SSH, which I’ll show later. After you’ve added the remote location, use the “push” command to commit your changes to the remote branch. The first parameter is the remote location (using the name you just specified in the “remote add” command), second parameter is the remote branch for the commit. This pushes your current branch to the specified remote branch. For example, if I give the command “git push origin master”, it pushes my current branch to the master branch of the remote repository named origin. If you don’t want to push your current branch, you can specify which local branch to push in the command like this: “git push origin local-branch:remote-branch”. This would commit my branch named local-branch to the branch named remote-branch on origin.

Kleinschs-Macbook:second.git nick$ git remote add origin ../first.git
Kleinschs-Macbook:second.git nick$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 239 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To ../first.git
 * [new branch]      master -> master

Now that we’ve got an initial commit in, let’s try the second way of connecting to a remote repository. The command “clone” copies everything from an existing repository and sets it up as a new repository. Again, in this example I’m using a local directory as the argument, but it can take other arguments including SSH.

Kleinschs-Macbook:second.git nick$ cd ..
Kleinschs-Macbook:tmp nick$ git clone first.git
Initialized empty Git repository in /Users/nick/tmp/first/.git/
Kleinschs-Macbook:tmp nick$ cd first
Kleinschs-Macbook:first nick$ ls
file1

Notice that we cloned “first.git”, so our clone is just named “first”. Let’s try adding a file through the newly cloned branch.

Kleinschs-Macbook:first nick$ echo 'Second file contents' > file2
Kleinschs-Macbook:first nick$ git add file2
Kleinschs-Macbook:first nick$ git commit -am'added second file'
[master 478a452] added second file
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2
Kleinschs-Macbook:first nick$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

If you compared the .git/config files between second.git and first (the cloned repository), you’ll notice that in the cloned repository, there’s an extra line about our master branch:

[branch "master"]
	remote = origin
	merge = refs/heads/master

This sets up our local branch to link to origin’s master branch. This means that when we do remote operations from our master branch, we don’t have to specify the remote location or branch. This means that in order to push our changes, we just have to do a “git push”.

Kleinschs-Macbook:first nick$ git push
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 300 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/nick/tmp/first.git
   1a603a8..478a452  master -> master

Now that we’re pushing changes out frequently, we need to be able to download those changes from the central repository. The “fetch” command gets all revisions from a remote repository.

Kleinschs-Macbook:first nick$ cd ../second.git
Kleinschs-Macbook:second.git nick$ git fetch origin
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../first
   1a603a8..478a452  master     -> origin/master

You’ll see it downloaded them and refers to them using the notation “remote-location/remote-branch-name”. The fetch command doesn’t move the changes into your existing working copy, you’ll need to take care of this yourself. In order to pull the changes into your current local branch, you do a normal merge.

Kleinschs-Macbook:second.git nick$ git merge origin/master
Updating 1a603a8..478a452
Fast forward
 file2 |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

Since the process of fetching and merging is a frequent one, there’s a command that combines them: “pull”. Doing a pull runs a fetch and merges the specified remote branch into your current local one.

Kleinschs-Macbook:second.git nick$ git pull origin master
From ../first
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Pulling and pushing is fairly simple, but there’s one common error I’ve run into that I’ll illustrate here. I’m going to push a commit from my second repository, then try to push a commit from my cloned repository.

Kleinschs-Macbook:second.git nick$ echo 'Third file contents' > file3
Kleinschs-Macbook:second.git nick$ git add file3
Kleinschs-Macbook:second.git nick$ git commit -am'added third file'
[master c114c2b] added third file
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file3
Kleinschs-Macbook:second.git nick$ git push
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 324 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To ../first.git
   478a452..c114c2b  master -> master
 
Kleinschs-Macbook:second.git nick$ cd ../first
Kleinschs-Macbook:first nick$ echo 'Fourth file contents' > file4
Kleinschs-Macbook:first nick$ git add file4
Kleinschs-Macbook:first nick$ git commit -am'added fourth file'
[master 17411ef] added fourth file
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file4
Kleinschs-Macbook:first nick$ git push
To /Users/nick/tmp/first.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '/Users/nick/tmp/first.git'
To prevent you from losing history, non-fast-forward updates were rejected.
Merge the remote changes before pushing again.
See 'non-fast forward' section of 'git push --help' for details.

When I tried to do the second push, it was rejected. This is because Git requires that push operations result in a fast forward merge. If push operations didn’t have to be fast forward there could be unresolvable conflicts on the central server, which would leave things in a bad state for other users. For this reason, you need to take care of conflicts locally before doing a push. The simple fix for this is to do a pull and make sure you’re up to date before trying to do a push. If your changes really have to go in, there are ways to override the fast forward requirement, see the Git book for advanced options.

Kleinschs-Macbook:first nick$ git pull
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/nick/tmp/first
   478a452..c114c2b  master     -> origin/master
Merge made by recursive.
 file3 |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file3
Kleinschs-Macbook:first nick$ git push
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 533 bytes, done.
Total 5 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
To /Users/nick/tmp/first.git
   c114c2b..5890924  master -> master

Now let’s go back over to the second repository to make sure our changes went through correctly.

Kleinschs-Macbook:first nick$ cd ../second.git
Kleinschs-Macbook:second.git nick$ git pull origin master
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From ../first
 * branch            master     -> FETCH_HEAD
Updating c114c2b..5890924
Fast forward
 file4 |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file4
Kleinschs-Macbook:second.git nick$ ls
file1	file2	file3	file4

Everything looks good! I spoke above about setting up repositories over SSH. You’ll need to have a valid account on the machine to connect to a Git repository. It’s usually helpful to set up a public/private key so you don’t have to specify the password every time. There are other way to connect, but they’re a bit more involved. Google and the Git Book are your friend here (start by looking up Gitosis). Here’s an example of the connect string to use with SSH.

Kleinschs-Macbook:second.git nick$ git clone ssh://nick@kleinsch.com/var/git/kleinsch.com.git/
Initialized empty Git repository in /Users/nick/tmp/second.git/kleinsch.com/.git/
remote: Counting objects: 2181, done.
...

I’ve made one mistake with SSH connect strings a couple of times now: this is not the same as the connect string for SCP. There’s no colon between the server and the path, unless you’re specifying a port. If you put one, you’ll just get a confusing error message, shown below.

Kleinschs-Macbook:second.git nick$ git clone ssh://nick@kleinsch.com:/var/git/kleinsch.com.git/
Initialized empty Git repository in /Users/nick/tmp/second.git/kleinsch.com/.git/
ssh: Could not resolve hostname kleinsch.com:: nodename nor servname provided, or not known
fatal: The remote end hung up unexpectedly

That covers the basics of remote operations. I’ll be doing one more post about Git focusing on remote branches.

Categories: How-To Tags:

Git Workflow – Part 2: Branches

August 26th, 2009 No comments

In the first tutorial, I showed how to set up a Git repository and commit basic changes. You could get a lot done using only those commands, but you’d be missing out on most of the benefits of Git. Most of that could be done in SVN or CVS fairly easily. In this tutorial, I’ll go through setting up branches and merging changes, one of Git’s main strengths. Git was built from the ground up for frequent branching. In other version control systems, you may use branches for releases or major events, but in Git your day to day workflow revolves around branches.

If you don’t want to go back through the first post, the following commands will get you in sync with what I set up in the first post.

mkdir first && cd first
echo 'firstEdit' > file1
git init
git add file1
git commit -m'First commit'
echo 'secondEdit' > file1
echo 'anotherFile' > file2
git add file2
git commit -am'Made a second commit!'

Branches have been a useful tool in version control for quite some time. They allow multiple versions of the same project to be actively developed. One of the most common use cases for branches is bug fixing. Let’s say you have a project that’s been released and you’re working on new features. Maybe you’ve committed a bunch of files but they’re not ready to go out to production. A user finds a showstopping bug that needs to be fixed immediately. Some people would pull the code from the production release, hack together a patch, and push it out. With branches, you can get the production branch, fix the bug, check in the changes, then switch back to your development branch and merge the changes. This tracks your changes so if you have to fix another production bug, nobody has to remember what went out in the last patch.

The command ‘branch’ with no arguments will tell you which branches exist and put an asterisk next to the branch on which you’re currently working. If you pass in a name, Git will create a branch with that name.

Kleinschs-Macbook:first nick$ git branch
* master
Kleinschs-Macbook:first nick$ git branch development
Kleinschs-Macbook:first nick$ git branch
  development
* master

The ‘checkout’ command switches to another branch. One shortcut you can take is the ‘-b’ flag to ‘checkout’ which creates the branch and checks it out.

Kleinschs-Macbook:first nick$ git checkout development
Switched to branch 'development'
Kleinschs-Macbook:first nick$ git branch
* development
  master
Kleinschs-Macbook:first nick$ git checkout -b my-dev-branch
Switched to a new branch 'my-dev-branch'
Kleinschs-Macbook:first nick$ git branch
  development
  master
* my-dev-branch

The command ‘gitk’ brings up a window that shows the state of your branches graphically. By default, it hides branches not related to the current branch. The flag ‘–all’ is useful to show all branches. This is useful in figuring out complicated branching and merging scenarios. The most useful part of the display is the top left corner, which shows your branches in order of commits. More recent commits are at the top. Doing this on my project brings up this.

Branch-Merge-1

All of our changes are in the same place, so the branches show up on the same commit. Let’s make some changes.

echo -e 'secondEdit\n\nadded a line' > file1

At this point if you change branches, your uncommitted changes will follow. Each modified file will show up with an ‘M’ next to it when you issue the checkout command.

Kleinschs-Macbook:first nick$ git checkout development
M	file1
Switched to branch 'development'
Kleinschs-Macbook:first nick$ cat file1
secondEdit
 
added a line

This seems a little strange, but can actually come in handy. Let’s say you’re working on something and it turns into a bigger project than you thought. You may want to work on that on a branch instead. In that case you can checkout onto a new branch, commit your changes, and keep working.

Kleinschs-Macbook:first nick$ git checkout -b testing-theory
M	file1
Switched to a new branch 'testing-theory'
Kleinschs-Macbook:first nick$ git commit -am'first commit while testing something'
[testing-theory 42a287a] first commit while testing something
 1 files changed, 2 insertions(+), 0 deletions(-)
Kleinschs-Macbook:first nick$ gitk

Branch-Merge-2

This allows you to take advantage of version control for the things you’re working on that aren’t ready to be shared with other team members. You can work on this test branch as long as you want. Let’s say at the same time, you have to fix a bug on the production release, which for this project will be the master branch. First, checkout the master branch.

Kleinschs-Macbook:first nick$ git checkout master
Switched to branch 'master'

Let’s first create a branch for fixing this bug. It’s quick and easy, and we can track our changes. Then we can make whatever changes are necessary.

Kleinschs-Macbook:first nick$ git checkout -b fixing-bug
Switched to a new branch 'fixing-bug'
Kleinschs-Macbook:first nick$ echo 'secondEdit - add to first line' > file1
Kleinschs-Macbook:first nick$ git commit -am'fixed a bug in file1'
[fixing-bug 645e620] fixed a bug in file1
 1 files changed, 1 insertions(+), 1 deletions(-)
Kleinschs-Macbook:first nick$ gitk --all

Branch-Merge-3

Now that we’ve fixed the bug, we’ll roll it out to production. Let’s merge the bug fix into the master branch. For this, we use the command ‘merge’. You must checkout the branch you’re merging to, then supply the branch you’re merging from as the argument to the merge command.

Kleinschs-Macbook:first nick$ git checkout master
Switched to branch 'master'
Kleinschs-Macbook:first nick$ git merge fixing-bug
Updating 941bde0..645e620
Fast forward
 file1 |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
Kleinschs-Macbook:first nick$ gitk --all

Branch-Merge-4

As you can see, we merged the changes into our master branch. This was actually a special type of merge: the fast forward merge. If the other branch already has all the commits from the current branch, Git will just add the commits from the other branch and point both branches at the same place. It’s like git is treating the commits from the fixing-bug branch as commits on the master branch.

Now let’s merge the changes from our testing-theory branch. This will conflict with the bug fix we just checked in, since both commits add to the first line. Usually Git is good at automatically merging, so changing two separate pieces of code in the same file won’t result in a conflict. In this example, we’ll have to resolve it. If conflicts are found, Git will leave markers in the conflicting files. After you fix the conflicts, you can run a commit to complete the merge.

Kleinschs-Macbook:first nick$ git merge testing-theory
Auto-merging file1
CONFLICT (content): Merge conflict in file1
Automatic merge failed; fix conflicts and then commit the result. 
Kleinschs-Macbook:first nick$ cat file1
<<<<<<< HEAD:file1
secondEdit - add to first line
=======
secondEdit
 
added a line
>>>>>>> testing-theory:file1

The first section shows the changes from master, the second shows the changes from testing-theory. Let’s keep both changes. I’m going to keep the first line from master and the last line from testing-theory.

Kleinschs-Macbook:first nick$ vi file1 
Kleinschs-Macbook:first nick$ cat file1 
secondEdit - add to first line
 
added a line
Kleinschs-Macbook:first nick$ git status
file1: needs merge
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	unmerged:   file1
#
no changes added to commit (use "git add" and/or "git commit -a")

Now we’re ready to finish the merge. You commit this the same as a regular commit. Since testing-theory doesn’t have the bug fix that we used to patch master, this will not be a fast forward merge.

Kleinschs-Macbook:first nick$ git commit -am'Merged changes from testing-theory branch'
[master d6132fa] Merged changes from testing-theory branch
Kleinschs-Macbook:first nick$ gitk --all

Branch-Merge-5

The picture here gets a little complicated, but it shows that our master branch now incorporates changes from both the fixing-bug and testing-theory branches.

The complicated stuff is over! Just two more bits to clear up. Let’s create a branch and make some changes.

Kleinschs-Macbook:first nick$ git checkout -b another-branch
Switched to a new branch 'another-branch'
Kleinschs-Macbook:first nick$ echo 'bad-change' > file2

If you don’t like the change and want to get rid of it, you can use the checkout command to get rid of it. SVN users: the ‘revert’ command in Git is not the same as the revert command in SVN! If you’re thinking of reverting changes made to a file, make sure to use the checkout command.

Kleinschs-Macbook:first nick$ git checkout file2
Kleinschs-Macbook:first nick$ cat file2
anotherFile
Kleinschs-Macbook:first nick$ git status
# On branch another-branch
nothing to commit (working directory clean)

Let’s say it turns out you didn’t need this branch, let’s get rid of it. You first need to switch away from this branch. Then use the ‘-d’ option to the branch command to delete unnecessary branches.

Kleinschs-Macbook:first nick$ git checkout master
Switched to branch 'master'
Kleinschs-Macbook:first nick$ git branch -d another-branch
Deleted branch another-branch (was d6132fa).
Kleinschs-Macbook:first nick$ git branch
  development
  fixing-bug
* master
  my-dev-branch
  testing-theory

You can even delete the branches you’ve committed. This won’t mess up your branching history, it just removes the branch label from those commits.

Kleinschs-Macbook:first nick$ git branch -d fixing-bug
Deleted branch fixing-bug (was 645e620).
Kleinschs-Macbook:first nick$ git branch -d testing-theory
Deleted branch testing-theory (was 42a287a).
Kleinschs-Macbook:first nick$ git branch -d my-dev-branch
Deleted branch my-dev-branch (was 5bd6207).
Kleinschs-Macbook:first nick$ gitk --all

Branch-Merge-6

This still shows the same history, we’ve just removed the named branches not in use. Finally, if you’re doing development, you may need to incorporate the changes that have gone into the master branch so you can start at the same point as your release.

Kleinschs-Macbook:first nick$ git checkout development
Switched to branch 'development'
Kleinschs-Macbook:first nick$ git merge master
Updating 941bde0..d6132fa
Fast forward
 file1 |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
Kleinschs-Macbook:first nick$ gitk --all

Branch-Merge-7

That’s about it for branching and merging. At this point the only thing the only major thing left is setting up remote operations. I’ll cover that in the next part of this tutorial.

Categories: How-To Tags: