Everything In Between

The brutally honest, first-person account of Meitar Moscovitz's life.

Archive for the ‘Programming’ Category

One Minute Mac Tip: Remove .DS_Store files from ZIP Archives

5 comments

The Mac OS X Finder has some nifty features, one of which is an exceptionally useful contextual menu item to create ZIP archives of folders. Unfortunately, the Finder also has some really, really annoying habits, one of which is to create a file named .DS_Store in each folder a user opens (when not in Column view). What this means is that if you create a ZIP archive on your Mac and then send it to someone who unzips it without the Finder (such as a Windows user using the Windows Explorer), the recipient will see a lot of litter in the form of useless and meaningless .DS_Store files.

If you’re not afraid of the Terminal, this can be avoided. Put the following lines in your ~/.profile (or similar):

alias rmds='find . -name ".DS_Store" -type f -print0 | xargs -0 rm'

What this does is creates a new command that you can use (rmds) which recursively finds and deletes any regular file named “.DS_Store” starting from the current directory. Thus, running this command in the folder you are about to create an archive out of will clean it first, and will prevent unnecessary confusion on the part of your archive file recipient.

Alternatively, another way to do this is to use the command-line zip program and an (admittedly more complicated) pipeline to remove the .DS_Store files after they have been added to the archive. To do that, use this series of commands:

zip -d ZIPfile.zip `unzip -l ZIPfile.zip | grep .DS_Store | awk '{print $4}'`

where, naturally, ZIPfile.zip is the ZIP archive you want to remove the .DS_Store files from. Creating an alias out of that command (and making it work for paths that contain spaces) is left as an exercise for the reader. ;)

As an aside, the alias, find and xargs commands are incredibly useful in their own right and can be used to do a lot of pretty amazing things. As always, man command will give you the nitty gritty.

Also as an aside, you can stop the Finder from creating .DS_Store files entirely when browsing network volumes (like Windows shares) with another command, documented in Apple’s Knowledge Base.

Written by Meitar

August 4th, 2008 at 1:07 am

How web designers can do their own HTML/CSS: Read Foundation Website Creation

7 comments

Last month, 37signals published a short but sweet post about why web designers should do the HTML/CSS implementations for their own designs. The bottom line is, as we’ve all been saying for a long time now, that the Web is not the same kind of medium as other mediums like print. It is a fundamentally different kind of canvas than most web designers are used to using. As a result, if you as a web designer are not intimately familiar with it, you’re not going to do great work.

designing for the web is a lot less about making something dazzle and a lot more about making it work. The design decisions that matter pertain directly to the constraints of the materials. What form elements to use. What font sizes. What composition. What flow. Those decisions are poorly made at an arm’s length.

I’ve worked with many web designers in the past who only did abstractions and then handed over pictures to be chopped and implemented by “HTML monkeys”. It never really gelled well. The things that got strong attention were all the things that Photoshop did well. Imagery, curvy lines, and the frame. All the around stuff, never the it stuff.

In other words, to do great web design you have to design in the Web, not in some other medium for the Web. I mean, serious magazine firm employs designers who don’t understand how to work with page layout programs like InDesign. Why, then, do so many web design agencies employ designers who don’t know how to work with web technologies, or even how to use programs like Dreamweaver? It doesn’t really make any sense, and it’s no wonder that the resulting implementation is rarely top-notch work.

But if you’re a graphic designer who doesn’t know much about Web technologies, what are you to do? Well, as a first step, I think you should pick up my new book, Foundation Website Creation. It’s available from all good booksellers (and probably some crappy ones) as of today. The book is targeted towards all manner of web professionals, including graphic designers and website producers, who want to learn more about what it takes to actually implement a site.

If I do say so myself, the chapters on XHTML and CSS are exceptionally thorough. The book doesn’t try to turn you into an exceptional programmer. Instead, it will explain the foundational concepts you need to know to understand how XHTML and CSS actually work, and in so doing will enable you to use the tools you already know to solve problems and get things done.

I think this book will be an excellent starting point for lots of designers and other web professionals. However, it is not going to take you from zero to hero—no book can. That’s why I recommend that, after you read Foundation Website Creation and have a solid grasp of what the technology can do for you and how it actually does it, you next take a look at these excellent books:

  • DOM Scripting by Jeremy Keith — if you’re a designer that needs to add a behavioral layer with JavaScript and Ajax to your pages, you need to read this book next.
  • Mastering CSS with Dreamweaver CS3 – if you’re familiar with Dreamweaver and want to keep using it to create standards-based web sites, then I recommend you follow Foundation Website Creation with this book by Stephanie Sullivan and Greg Rewis to take your Dreamweaver skills to the next level.

As always, most of all, have fun. Because if you’re not having fun, you’re not going to make good web sites no matter what you know.

Note: As of this writing, the book listing on Amazon still publishes the wrong author list, which is very frustrating but out of my hands. At least the image of our book’s front cover lists the correct authors.

Fix Subversion “checksum mismatch” error by editing .svn/entries file

18 comments

I can’t explain why this happened because in my several-year-long history with Subversion, I’ve never experienced this issue once. However, today, I fell into the (arguably) unfortunate circumstance of running into a most disturbing error from SVN. When trying to commit my changes, SVN barfed at me and complained of a “checksum mismatch”. It looked something like this:

Transmitting file data ..svn: Commit failed (details follow):
svn: Checksum mismatch for '/Users/maymay/Sites/path/to/subversion/working/copy/.svn/text-base/working-file.php.svn-base'; expected 'cde4d8fbd5c623da3a8b1a343aa7b3f4', actual: '270b2f20804a5fcdbd15eec5910f6e3f'

Of course, the path/to/subversion/working/copy bit was the path to my working copy file’s parent directory and the working-file.php was an actual file in my working directory.

I think what Subversion was trying to tell me is that its hashed copy of the working-file.php file and the copy I was asking it to commit weren’t the same. It would be nice if it would actually tell me why that happened, but it’s clearly more temperamental than that.

Anyway, to fix this issue (at least for now…?) I simply checked out a new working copy of this directory, examined the .svn/entries file from it and sure enough, found the actual checksums in there, just as Subversion reported expecting. I simply copied those expected checksums into the .svn/entries overwriting the old actual checksums and, voila, Subversion has been fooled. After that, I could commit my changes.

Step by step (because I’m sure someone, somewhere, somehow, will run into this again—if it’s not me that is!), this procedure looked like this:

  1. Copy the “expected” and “actual” checksums Subversion reports to you to a new text file so you can refer to them later. Note which one is the expected and which is the actual checksum.
  2. Go to where the problem is (that is, cd path/to/broken-files-parent-dir/.svn)
  3. Open the entries for editing (for example, vim entries)
  4. Search the file for the actual checksum.
  5. Replace it with the expected checksum. Be careful not to change any other part of the file.
  6. Save the file.
  7. Try to svn commit again.
  8. Lather, rinse, and repeat for any other files Subversion barfs at you about.

I’m sure this is not an elegant or even the recommended solution to this problem. The truth is I never bothered to look up what the recommended solution is, because it seems to me that any code repository that can’t guarantee what I get out of it is the same as what I put into it isn’t a versioning system I really want to trust the “recommended” solution of, anyway.

Also known as: this is another reason why I like git better now.

Written by Meitar

June 17th, 2008 at 9:07 am

Ridiculously simple JavaScript version string to object parser

6 comments

In any kind of development, you often have to deal with version strings. Typically, these version strings are just a dot-separated list of numbers that represent different versions of the software. I recently had a need to compare two version numbers against one another to determine which one was newer. This is useful if, say, you’re building an application that wants to check its current version against the “latest” available version.

In JavaScript, this is thankfully pretty trivial. My solution is to just parse the version strings with a simple function and return them as objects with appropriate properties whose values are integers. Once in this form, we can compare them with simple math.

function parseVersionString (str) {
    if (typeof(str) != 'string') { return false; }
    var x = str.split('.');
    // parse from string or default to 0 if can't parse
    var maj = parseInt(x[0]) || 0;
    var min = parseInt(x[1]) || 0;
    var pat = parseInt(x[2]) || 0;
    return {
        major: maj,
        minor: min,
        patch: pat
    }
}

Using this new object, we can now compare two versions really simply:

var running_version = parseVersionString('3.5.2');
var latest_version = parseVersionString('3.4.5');
if (running_version.major < latest_version.major) {
    // A major new update is available!
} else if (running_version.minor < latest_version.minor || running_version.patch < latest_version.patch) {
    // A new minor or patch update is available.
} else {
    // We are running the latest version! No need to update.
}

Written by Meitar

June 15th, 2008 at 5:39 am

Arbitrarily exclude posts from displaying in WordPress

9 comments

When hacking away at WordPress sites, often times you’ll find yourself in a situation where you need to filter out certain posts from displaying on some pages, such as the home page. There are a lot of ways to do this, but few are perfect. Recently, I had the need to do this and went searching for pre-existing solutions.

I came across Vaibhav’s post on the topic and noted that his solution uses the query_posts() function to alter WordPress’s query object before The Loop has run. While this is a great solution if your exclusion criteria is simple enough to be supported directly by the WordPress query object, other times the query_posts() function doesn’t provide you with the hook you need.

In these cases, you can run the original query, note any modifications you need to make, and then create a new, modified query and display the results you get from running that one instead. For instance, you might need to do this if you need to exclude posts based on category and, say, the beginning of their title, or their category and a certain piece of content in the post itself, or all three, or any other combination you can think of.

Another advantage of this technique over simpler ones is that this method maintains the same behavior you’d expect to see in every other way. Most notably, this means that if you’ve told WordPress to display the 10 most recent posts on the home page (in the WordPress settings), you’ll still see ten posts on that page even after you exclude some of them.

To do something like excluding posts if they are in the “Uncategorized” category (traditionally the category with an ID of 1 in WordPress) and their title begins with “Some title”, you can do this:

// original query runs in The (real) Loop first
while ( have_posts() ) : the_post();
    // detect pots matching our exclusion criteria
    if (in_category(1) && (0 === strpos(the_title('', '', false), 'Some title')) ) {
        $wp_query->post_count++; // increment the post counter
        continue;
    }
    endif;
endwhile;
// now make a new query and show the posts for real, with the adjusted post count and filtering
$my_new_query = new WP_Query($query_string.'&showposts='.$wp_query->post_count);
// do another The Loop (and display the results this time)
while ( $my_new_query->have_posts() ) : $my_new_query->the_post();
    // detect and exclude these same posts
    if (in_category(1) && (0 === strpos(the_title('', '', false), 'Some title')) ) { continue; }

// ...the rest of the WordPress template goes here...

This is neat because it gives you the capability to define arbitrarily complex exclusion patterns and directly modify your new query object however you like before you execute it. Once you know this works, you’ll probably want to extract the filtering code into a function. Using the above example, your new code might look like this:

// define criteria for filtering
function matches_filtering_criteria () {
    if (in_category(1) && (0 === strpos(the_title('', '', false), 'Some title')) ) {
        return true;
    } else {
        return false;
    }
}
// original query runs in The (real) Loop first
while ( have_posts() ) : the_post();
    // detect pots matching our exclusion criteria
    if (matches_filtering_criteria()) {
        $wp_query->post_count++; // increment the post counter
        continue;
    }
    endif;
endwhile;
// now make a new query and show the posts for real, with the adjusted post count and filtering
$my_new_query = new WP_Query($query_string.'&showposts='.$wp_query->post_count);
// do another The Loop (and display the results this time)
while ( $my_new_query->have_posts() ) : $my_new_query->the_post();
    //
    // detect and exclude these same posts
    if (matches_filtering_criteria()) { continue; }

// ...the rest of the WordPress template goes here...

For more information on these functions, see:

Written by Meitar

June 6th, 2008 at 1:11 pm

I’m getting a book published and it’s called Foundation Website Creation

9 comments

For those who have been wondering what is keeping me so busy these days, the answer is that I’m working on the final stages of a book that is getting published as one of three co-authors. Not only am contributing three chapters (the technical chapters on (X)HTML and CSS, specifically), but I am also technically reviewing the entire book.

My co-authors on the book, called Foundation Web Standards Foundation Website Creation (you can pre-order now) and published by Friends of ED, an Apress company, are Jonathan Lane of Industry Interactive, Inc. and Joe Lewis, who blogs at Sanbeiji.com. I’m not going to say much more until after the book is released in late July.

For the eager, here’s the description of the book posted on the Friends of ED website:

Foundation Website Creation explores the process of constructing a web site from start to finish. There is more to the process than just knowing HTML! Designers and developers must follow a proper process to flush out goals and objectives and determine requirements both prior to, and during project development.

Large Web projects are rarely completed by a single person. Producers, project managers, designers, developers, writers, and editors all play critical parts in a project’s evolution. This book provides an overview of the entire process, and also shows project development from the perspective of these different roles. It introduces the key concepts and duties performed by every member of such a team, and gives you the skills necessary to tackle projects like a professional.

It’s quite exciting getting a book out, and it’s quite a bit more work than I’d have ever originally thought. That being said, it’s extremely rewarding. There’s a lot more work I need to do on it between now and the time it gets released to publishing, so, well…back to work I go.

Now you all know where I’ve been spending my time writing.

Quick ‘N’ Dirty Drupal Module SVN Tagging Script

one comment

In a (rather beastly) project at work today, I found myself needing to import a significant number of contributed Drupal modules into Subversion vendor branches to prepare for custom development. To do so manually would have been quite the hassle, so after downloading the appropriate tarballs and creating a module_name/current directory under my vendor/drupal/modules vendor branch directory, I concocted this little (relatively untested) script to handle the mass tagging operations I needed to perform.

for i in *; do
    v=`grep 'version = "' "$i/current/$i/"*.info |
      cut -d ':' -f 2 |
        sed -e 's/^version = "/v/' -e 's/"$//'`
    svn cp "$i/current" "$i/$v"
done;

It’s a bit buggy for some modules that have multiple .info files, but I’m sure a few more pipeline stages can fix that. (Which, because I’m done with this at the moment, I will leave as an exercise to the reader.)

Chalk this one up as another testament to the power of shell scripting and how it can help every developer get their job done faster.

Written by Meitar

May 14th, 2008 at 4:46 am

How to import CVS code repositories into Git using `git cvsimport`

10 comments

This should be straightforward, but it’s not. To import (not track, but just import) code from a remote CVS repository to a local git repository, you need to do the following:

  1. Be certain you have the git-core package installed on your system and that this package includes the git-cvsimport command. You can run git help -a | grep cvsimport to verify this.
  2. Be certain you have the cvsps command-line tool installed. This does not come with the git suite of tools, so you’ll need to get it separately. If you’re a lazy Mac OS X user, like me, you can use MacPorts: sudo port install cvsps. Otherwise, get it from the source.
  3. Prepare your CVS login information for the remote server before you run git cvsimport. You need to do this so that the git tool will be able to log you in to the CVS server automatically. The command for this looks like:
    CVSROOT=:cvs-login-method:cvs-user-name@cvs.server.name:/path/to/CVS/root cvs login

    For example, if you’re pulling code from the anonymous CVS server that runs on Drupal.org, you might use this: CVSROOT=:pserver:anonymous@cvs.drupal.org:/cvs/drupal-contrib cvs login. This command will prompt you for the password for the user you specified at the server you specified (for anonymous access, the password is almost always anonymous) and will hash this in the ~/.cvspass file for future use by CVS

  4. Finally, run the git cvsimport tool, and specify the proper options. Using the Drupal example above, your command might look like this:
    git cvsimport -v -d :pserver:anonymous@cvs.drupal.org:/cvs/drupal-contrib contributions/modules/module-name

    This would login to cvs.drupal.org using the CVS‘s pserver login method, provide the username anonymous and the password you specified in the previous step that is hashed in ~/.cvspass, set the CVS document root to /cvs/drupal-contrib, and pull the code located at contributions/modules/module-name into the current working directory as a git repository.

This works pretty nicely, and creates a git repository just as though you’d created it with git init in the current working directory.

If you get an error that looks like this:

AuthReply: cvs [pserver aborted]: descramble: unknown scrambling method

then you’ve most likely specified the CVS document root incorrectly. Most notably, git cvsimport does not understand a CVS document root wherein the password is specified in the document root URL itself. So, for example, git cvsimport -d :pserver:password:username@cvs.server.name:/path/to/CVS/root code/to/checkout will not work. Omitting the password and the separating colon from the URL should fix it.

Written by Meitar

April 15th, 2008 at 4:06 am

Posted in HOWTO,Mac OS X,Programming,Unix/Linux

Tagged with

HowTo: Use git for personal development when everyone else is using Subversion (part 2)

one comment

When we left off, you had just finished transforming a remote Subversion repository into a git repository and optimizing it to save you some space. Now that you have a git repository, what do you do?

First things first. Once you have an idea of what work you want to do, you should give yourself a space to do this work without disturbing anybody else’s work. Do this by making a new, personal branch. Unlike Subversion and some other centralized version control systems, git makes it possible to do make all kinds of changes to your repository, including making branches, and even save those changes without having to republish everything back to the central repository server at each step. In other words, if you thought Subversion branches were “cheap,” you’ll love git’s branches.

Also unlike Subversion, which stores its branches in completely separate pathnames, git keeps all branches in the same filesystem tree separated only with metadata (in .git/refs/remotes for remote branches and in .git/refs/heads for local branches, to be a bit more precise), so you don’t have to create lots of different directories for all your branches (unless you want to). With no branches defined, you’re working in the “master branch,” or “the trunk” by default.

git branch
* master

By saying git branch you ask git to print a list of all (local) branches. The one with the asterisk marks the current branch, the one you’re using at the moment you run the command. Since there are no branches, you’re currently in the “master” branch. But we don’t want to make changes here, we want to make changes in our own private branch, so we’ll make a new one.

git checkout -b new_branch_name

This will create a new branch with the name new_branch_name and immediately switch to it. Notice that you’ve made absolutely no changes to the filesystem itself; only the git metadata has been altered. Saying git branch again will show you the change:

git branch
  master
* new_branch_name

Also note that since we haven’t comitted any changes, we don’t need a commit message (or “log message”) for creating this branch. We’ll add one later, when we need it. Now go ahead and write some code in your new branch. At any time, you can create a new branch in the same way you added the first. Each new branch is created at the HEAD (“latest”) revision of whatever branch you’re currently working in.

git checkout -b another_branch
Switched to a new branch "another_branch"
git branch
  master
  new_branch_name
* another_branch

To switch back to any other branch, simply git checkout that branch again:

git checkout master
Switched to branch "master"

If you want to delete a branch you don’t like, that’s easy too:

git branch -d another_branch
Deleted branch another_branch.

Keep in mind that throughout all of these branch creation and deletion actions, the only thing that’s being altered is the git metadata. That’s why it’s so cheap to create new branches. If you ever have a new idea you’re working on, it’s recommended that you create a branch for it, even if that branch is so short-lived it never gets published.

So you have a new local branch, and you’ve been working as you normally do for a few minutes, creating files, editting them, and so on. Running git status now will ask git to show you the changes you’ve made to your filesystem. If you’ve created any files in new directories that git doesn’t know about, it will simply report that directory. If you’ve made new files in directories git does know about, it will list all those files explicitly.

git status
# On branch cartoon_contests
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	sites/default/modules/cartoon_contests/
#	sites/default/modules/factiva/.factiva.module.swp
#	sites/default/modules/testfile
#	sites/default/settings.php
nothing added to commit but untracked files present (use "git add" to track)

In the above sample output, I’m working on a new Drupal module for a web site. I’ve created a new directory, sites/default/modules/cartoon_contests/ (note the trailing slash), and I have several untracked files. One is my vim swap file for a different module, .factiva.module.swp, one’s an unimportant testfile, and the last is the Drupal configuration file, settings.php.

The only thing I want to commit is the new cartoon_contests directory, and all the files within it. Like Subversion, I have to tell git that I want to track this directory, which is done simply by saying git add cartoon_contests. Unlike Subversion, future invocations of git status let me see everything that git is going to go in the next commit.

git status
# On branch cartoon_contests
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	new file:   sites/default/modules/cartoon_contests/cartoon_contests.info
#	new file:   sites/default/modules/cartoon_contests/cartoon_contests.module
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	sites/default/modules/factiva/.factiva.module.swp
#	sites/default/modules/testfile
#	sites/default/settings.php

The “Changes to be committed” section of the output is called the staging area, or the index. In this way, I can prepare all the changes I want to commit before I do so, making sure they’re perfect before I actually commit them to the git repository. At any time before I commit, I can make additional modifications, such as git adding more files or directories, git reseting to unstage all (or some) of my changes, etc. git help reset also has a number of handy explanations with examples for different things you might need to do at this point.

If you were using svn:ignore, equivalent functionality exists in git. Simply append file glob patterns, one per line, to the $GIT_DIR/info/exclude file in your git repository. Like so:

echo -e "*.swp\nsites/default/settings.php" >> .git/info/exclude ; git status
# On branch cartoon_contests
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	new file:   sites/default/modules/cartoon_contests/cartoon_contests.info
#	new file:   sites/default/modules/cartoon_contests/cartoon_contests.module
#

If you’ve got many of these, you can use git svn show-ignore >> .git/info/exclude to search through your old Subversion repository and look for any and all ignores, automatically adding them to git’s exclude list. (Checkout Tsuna’s blog entry on learning git for more tips like this.)

Finally, after you’ve done some of your work and you’ve finished staging your changes, you’re ready to commit them to the repository. On the other hand, if you hate what you’ve done and want to undo it all, you can say git reset --hard HEAD to throw away all your local changes. To throw away changes to just a single file, just checkout that file again by saying git checkout filename. This is the equivalent of Subversions svn revert filename command.

Before you actually make your first commit, however, you should properly introduce yourself to git. You don’t have to do this because git will try to figure out who you are by itself (details explained in detail here), but you probably should at least create global defaults for your user (which git will store in ~/.gitconfig). If you want to, you can also create per-repository defaults (which git will store in .git/config), or even system-wide defaults for all users of this computer (which git will store in /etc/gitconfig). To do so, say this:

git config --global user.name "Your Full Name"
git config --global user.email "you@example.com"

This will create the file ~/.gitconfig if it doesn’t alreay exist and will write your name into it. You can also just edit the file directly yourself instead of using git config commands.

Like Subversion, committing will create a saved, fixed point-in-time that marks the changes you have made to your files. Like branches, commits are also very cheap in git, so go ahead and commit at any time you like. Remember to stage your files (by git adding them), and then just git commit.

git add filepattern
git commit -m "My very frst git commit!"
Created commit ef483c1: My very frst git commit!
 5 files changed, 58 insertions(+), 12 deletions(-)

If you forget to specify a commit log message (-m "log message") on the command line, or if you want to enter a multi-line commit log, git will prompt you for it in your favorite $EDITOR. You can view a history, including all the log messages, for your project with git log. You can even the view logs in a number of pretty formats. Check git help log for more information.

If you want to change anything about the commit you just made, such as the author, you can just run git commit again with the --amend flag added to the command. Notice the typo in the commit log? Fixing it is really easy:

git commit --amend -m "My very first git commit!"
Created commit 88602f6: My very first git commit!
 5 files changed, 58 insertions(+), 12 deletions(-)

Finally, with your new code commited to your local git branch, it’s time to share that code with your colleagues who are (for some inexplicable reason) still using Subversion. This is also extremely simple. Just say git svn dcommit. (That’s right, dcommit, not just commit. I don’t know why….)

Not sharing your changes via Subversion, but with a patch instead? git diff -p will generate patches for you. See git help diff-files and look for the “GENERATING PATCHES WITH -P” section.

If you found this helpful, you may also enjoy an alternative tour for beginners from Carl Worth.

Written by Meitar

March 28th, 2008 at 3:20 am

Posted in HOWTO,Mac OS X,Programming,Unix/Linux

Tagged with

HowTo: Use git for personal development when everyone else is using Subversion (part 1)

5 comments

Let’s just jump into it.

Using Mac OS X, first make sure you have the git core installed as well as the git-svn components. Unlike other version control systems, git is not one monolithic program but a collection of smaller utilities, and the Subversion conduits are a subset of these utilities. The git-Subversion utilities themselves depend on having the Perl::Subversion bindings installed for Perl 5.

For the lazy MacPorts user, simply run:

sudo port install git-core +svn

This will install the git-core, the git-svn packages, as well as all the documentation for git and any required dependencies you don’t already have. Note that the documentation (man pages) is installed in /opt/local/man, which may not be in your default $MANPATH, so be sure to add that directory if man git returns a “No manual entry for git” error.

Alternatively, if you don’t want to use MacPorts, you can download a pre-compiled Mac OS X binary that includes git, the git docs, and the git-svn package from the git web site that comes complete with a standard GUI installation procedure.

Next, initialize a new git repository that tracks a remote Subversion one. This allows you to work privately using git, but to collaborate with other people who are using Subversion. Running

git svn init svn://my.svn.server/path/to/svn/repo workingcopy

will give you an empty git working copy named workingcopy configured to use the remote Subversion repository at svn://my.svn.server/path/to/svn/repo. This step is analogous to the need to run svnadmin create repo_db, to initialize a new repository database (where all the file versioning information will be stored). Unlike Subversion, git’s distributed database means that the working copy itself is also the location of the repository database, so there’s no need to deal with two filesystem paths anymore.

Next, change directory to your working copy, and run

cd workingcopy
git svn fetch

to populate your new, empty git working copy (and repository) with all the files from the remote Subversion repository.

Now that you have filled your git repository with a lot of data, if you want to, you can now also save a significant chunk of disk space by repacking that data into a more single, efficient, native packed git archive format (a .pack file). The git-repack -a command is used to do this, and its manual page says:

Instead of incrementally packing the unpacked objects, pack everything referenced into a single pack. Especially useful when packing a repository that is used for private development and there is no need to worry about people fetching via dumb protocols from it.

According to some sources, this can turn a 353MB Subversion repository into 31MB of git pack. Say:

git repack -a -d -f
Generating pack...
Counting objects: 284
Done counting 4475 objects.
Deltifying 4475 objects...
 100% (4475/4475) done
Writing 4475 objects...
 100% (4475/4475) done
Total 4475 (delta 1876), reused 0 (delta 0)
Pack pack-a115c320ff9c9968248bd250bdfea3110d0f0c1a created.
Removing unused objects 100%...
Done.

to perform the compression. For even greater savings, increase the compression by stipulating a high --window option, such as git repack -a -d -f --window=100. (--window defaults to 10—the higher the window, the harder git-repack will try to compress your stuff.) This turned a 36MB Subversion repository in one of my projects to a 20MB git pack. As always, your mileage may vary.

Congratulations, you have transformed your old Subversion repository to a git repository. All that’s left to do now is to get to the coding. Perhaps start by making a local (cheaper than cheap!) git branch….

That was easy, right? Most things in git are, in fact, that easy. If you’ve never used other version control systems before, be grateful. If you have, you can breathe a sigh of relief. Still not convinced? Don’t take my word for it…ask Linus Torvalds (or Randall Schwartz).

Written by Meitar

March 26th, 2008 at 1:54 am

Posted in HOWTO,Mac OS X,Programming,Unix/Linux

Tagged with