Archive

Archive for August, 2009

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:

A Simple Git Workflow

August 15th, 2009 No comments

I just started using Git for source control. Having used CVS and SVN extensively, I thought I had a decent background on version control and would be able to pick it up quickly. I quickly was overwhelmed by the amount of concepts and explanations needed in the documentation. Hint to the folks writing the Git book: start with simple concepts and build up from there. I don’t need to know how Git stores its files in the first chapter. I don’t need to know what a fast forward merge is. Give me one chapter that has a simple workflow example, then jump into the explanations of the internals and advanced features. I had to read through 50 pages of the book to figure out a basic remote workflow. Here are some of the bits I’ve gleaned. I’m still a Git beginner, so tips are always appreciated.

I’ll assume you have Git set up already, there are tutorials on the web for the wide variety of supported platforms. Once you’re set up with Git, you should be able to run ‘git –version’ at the command line and see a version string (like “git version 1.6.3.2″). All git commands are run in the format ‘git COMMAND_NAME OPTIONS’. Running ‘git –help’ will list all commands. Running ‘git help COMMAND_NAME’ will give a man page about that command. For example, to get information about the add command, you can run ‘git help add’.

Setting up a Git repository is simple. You can use an existing directory or create something from scratch. I’ll start out fresh. The ‘init’ command sets up a new repository.

Kleinschs-Macbook:tmp nick$ mkdir first && cd first
Kleinschs-Macbook:first nick$ echo 'firstEdit' > file1
Kleinschs-Macbook:first nick$ git init

Now we’re set up with a Git repository in this directory. The ’status’ command gives you information about your working set.

Kleinschs-Macbook:first nick$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	file1
nothing added to commit but untracked files present (use "git add" to track)

To make a commit in Git, you first do an ‘add’ of all files you want to be included in the commit, then a ‘commit’. The commit command will prompt for a message using your favorite editor, or you can use the ‘-m’ flag to add the message at the command line.

Kleinschs-Macbook:first nick$ git add file1
Kleinschs-Macbook:first nick$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
#	new file:   file1
#
Kleinschs-Macbook:first nick$ git commit -m'First commit'
[master (root-commit) 4cc0433] first file
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
Kleinschs-Macbook:first nick$ git status
# On branch master
nothing to commit (working directory clean)

Let’s say we want to make a change. We’ll modify the first file and add another.

Kleinschs-Macbook:first nick$ echo 'secondEdit' > file1
Kleinschs-Macbook:first nick$ echo 'anotherFile' > file2
Kleinschs-Macbook:first nick$ git status
# On branch master
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   file1
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	file2
no changes added to commit (use "git add" and/or "git commit -a")

Git detects that we’ve changed one file and added another. If you want to see the changes you made, you can use the ‘diff’ command to show a diff of the files.

Kleinschs-Macbook:first nick$ git diff file1
diff --git a/file1 b/file1
index dc2bdc4..1837f2f 100644
--- a/file1
+++ b/file1
@@ -1 +1 @@
-firstEdit
+secondEdit

We could add the change and commit, but there’s a slightly easier way. As the status output describes, you can use the ‘-a’ flag for commit to automatically commit all modified files. It will not add new files, you’ll still have to do add those yourself. Let’s add the second file and commit the whole thing.

Kleinschs-Macbook:first nick$ git add file2
Kleinschs-Macbook:first nick$ git commit -am'Made a second commit!'
[master 74ec253] Made a second commit!
2 files changed, 2 insertions(+), 1 deletions(-)
create mode 100644 file2
Kleinschs-Macbook:first nick$ git status
# On branch master
nothing to commit (working directory clean)

The last thing to cover for right now is looking at past history. You use the ‘log’ command to view commit history.

Kleinschs-Macbook:first nick$ git log file1
commit 8ebf88b3d99309c1bd245156459a24549cf11ee8
Author: Nick Kleinschmidt <nick.kleinschmidt@gmail.com>
Date:   Sat Aug 15 09:28:26 2009 -0400
 
    Made a second commit!
 
commit 7801dc66b2b3b5029e888ad35e5f0405584b4ff1
Author: Nick Kleinschmidt <nick.kleinschmidt@gmail.com>
Date:   Sat Aug 15 09:24:47 2009 -0400
 
    first commit
Kleinschs-Macbook:first nick$ git log file2
commit 8ebf88b3d99309c1bd245156459a24549cf11ee8
Author: Nick Kleinschmidt <nick.kleinschmidt@gmail.com>
Date:   Sat Aug 15 09:28:26 2009 -0400
 
    Made a second commit!

With this setup, you can work locally, changing and committing to your hearts content. At this point, it’s fairly similar to most traditional version control systems. There’s still a lot to cover! Next time, I’ll get into setting up a remote repository, then we’ll dive into branching and merging.

Categories: How-To Tags:

Setting up WordPress on Debian 5.0

August 1st, 2009 No comments

I’ll assume you’re starting with a stock Debian 5.0 system and have set up sudo access for your account. I’ll be using the user nick as my personal user for this setup.

First we need install the prerequisites: Apache, PHP, and MySQL. It’ll ask you for a root password for MySQL, make sure you hold onto that. We’ll need it later.

sudo apt-get install apache2 mysql-server php5 php5-mysql

Now we need to make sure that Apache is configured with the modules needed for Wordpress.

sudo a2enmod rewrite
sudo a2enmod php5

WordPress uses a MySQL database to store your blog posts and comments, so we need to create a MySQL database for wordpress. MySQL will ask you for the root password you created before. Make sure to save the password you set up for the wordpress user, as this is what WordPress will use to connect to the database.

mysql -u root -p
CREATE DATABASE `wordpress`;
grant all privileges on `wordpress`.* to 'wordpress'@localhost identified by 'ANOTHER-PASSWORD'; 
flush privileges;

Need to set up WordPress with a directory so we can use it. Download WordPress from their site and stick it in your home directory.

cd /var/www
sudo mkdir sites && cd sites
sudo cp ~nick/wordpress-2.8.2.tar.gz .
sudo tar xzvf wordpress-2.8.2.tar.gz
sudo touch wordpress/.htaccess
sudo chown -R nick:www-data wordpress
sudo chmod -R g+w wordpress

We changed the group and gave write permissions so WordPress will be able to set up its own config files. We set up the .htaccess file in advance because it’s easier to let WordPress change it based on the URL settings.

In order to serve the website, we need to set up an Apache Virtual Host. Create a file in /etc/apache/sites-available (mine is kleinsch.com) for your site and add the following code.

<VirtualHost *:80>
        ServerName kleinsch.com
        ServerAlias www.kleinsch.com
        ServerAdmin youremail@yourhost.com
        DocumentRoot /var/www/sites/wordpress
        <Directory /var/www/sites/wordpress>
                Options FollowSymLinks
                AllowOverride All
        </Directory>
</VirtualHost>

Enable the site within Apache and restart:

sudo a2ensite kleinsch.com
sudo /etc/init.d/apache restart

You should see no warnings. Open up your browser and navigate to ‘http://yoursite.com/wp-admin/install.php’.

The first page will tell you WordPress needs to create a config file, we want it to do that. On the next page, enter the database information you set up above. Leave the defaults for the encoding and table prefix. Enter a title for your blog, and you’re up and running!

Categories: How-To Tags: ,