By way of the previous post, a thought of the day:

resoundingsalmon: Search Engine Optimization people are evil. They want to eat your fucking soul.



I would feel better about the latest turn in Twilight Princess if, when you listened in on the guards in Castle Town, they had a conversation like this one:

Bell: Dammit, I forgot my lunch sack again.
Frid: Ha, I hear that kid from Ordon will fetch any damn thing.
Bell: No shit? Tell him my lunch sack is vital to Hyrule’s security!

And then they laugh like Tom Nook.


git equivalent to “svn copy” for forking files with history?

As might be obvious from my previous post, I don’t yet grok git. (It took three tries over about a week to figure out what I posted there.) My other major question as a dual git/subversion user is how do I svn copy in git? I don’t see that adequately answered anywhere.

The most common use of svn copy is to branch, which is precisely what I don’t mean here. git seems to promote branches to a first-order concept, in that the entire git repository exists across branches, and there are specific commands for branching and merging. You can’t have a nonstandard trunk/branch/tag hierarchy like you do sometimes in subversion, because there is no hierarchy. git branches are completely orthogonal to your file structure.

Git From the Bottom Up suggests (perhaps a little facetiously) phrasing your problem in git’s language in order to understand:

Understanding commits is the key to grokking Git. You’ll know you have reached the Zen plateau of branching wisdom when your mind contains only commit topologies, leaving behind the confusion of branches, tags, local and remote repositories….

In these terms, you find branches are really names for other commits besides the master head main trunk commit. It’s not really that branches are first-order things, but that branches are names for commits instead of files. Either way, they’re completely orthogonal to the filesystem.

Looking again just now for the answer to my question, I found this thread, which illustrates git’s current position on copying, and how it’s contrary to this second use of svn copy that I’m trying to figure out:

svn copy::
Duplicate something in working copy or repository, remembering history.
cp A B; git add B::
Git doesn’t have a direct equivalent of svn copy. It’s arguable whether it needs it once the user knows they can git-add so easily.

Git wins. Git’s ability to detect copies after-the-fact, mean that a git-copy isn’t necessary.

svn copy is more like git checout -b, i.e. it’s primary purpose is not to “copy” things, it is to create branches. You generally do not copy code (I hope).

Well, in fact, I often do copy code with svn, because I want to fork a file with history. Often I discover when I’m working on (say) some class, I’ve accreted unrelated functionality around the class’s real work, and I need to separate it out. Obviously I can do that just fine and check both parts in, but if I naïvely fork one file in twain—by doing a real file copy and adding the new file, say—the new one will lose all its history. The first commit git will know about for it is the one where it appears fully formed from Zeus’ head, though it happens to share an equivalent blob with some other file in the commit.

In git terms, you can see why it’s not obvious how to copy with history: to duplicate svn copy A B, you want git to understand when you ask about B’s history to include all of A’s previous commits. It’s as though you want to change all A’s commits retroactively to include B, sort of. It’s more about the behavior of the tools than anything you can articulate in a git repository’s data.

So I looked for behavior: lo and behold, Andy Parkin’s message above notes that git can “detect copies after-the-fact,” and I guess he means for example git log’s -C and --find-copies-harder options. According to the manual, this seems to be exactly the behavior I need:

Detect copies as well as renames. See also --find-copies-harder.
For performance reasons, by default, -C option finds copies only if the original file of the copy was modified in the same changeset. This flag makes the command inspect unmodified files as candidates for the source of copy. This is a very expensive operation for large projects, so use it with caution. Giving more than one -C option has the same effect.

If only it worked that way. See the terminalcast I did showing what I mean: once I duplicate the file, svn log doesn’t show fred’s initial commit in wilma’s history, even with the -C or --find-copies-harder flags.

I would be delighted to be wrong, but as far as I can tell, it’s not possible to fork files in git, while it’s trivial with svn copy.


Moving commits from git to subversion

It’s fairly well documented what to do if you have a subversion repository and want to develop on it with git. What if you have a project you started in a git repository, but now need to publish it to a subversion repo?

After several attempts and resets, this seems to be what you have to do to check a project you built with local git into an arbitrary place in a subversion repository.

  1. Make a new git repo: mkdir ~/import; cd ~/import; git init
  2. Make the new remote directory in the svn repo: svn mkdir http://example.com/proj/
  3. Link up with the empty path using git-svn: git svn clone -T '' http://example.com/proj/
  4. Add your original repo as a remote: git remote add dev file:///home/username/work/proj
  5. git pull dev master to pull in all the original git repo’s commits.
  6. git svn rebase to rebase all the commits on top of the svn commit.
  7. In my case, the rebase halted on some commits in the git history where I added files. I had to git add the files manually, then git rebase --continue.
  8. git svn dcommit (or with -n to check… but it’s just a list of commit IDs, so it sure didn’t make me feel that much better about doing it)

You can then really check it worked by comparing the subversion content to your git repo:

  1. cp -R ~/work/proj proj-git
  2. rm -r proj-git/.git
  3. svn export http://example.com/proj/ proj-svn
  4. diff -rub proj-svn proj-git

As usual in UNIX, silence is golden.


New light

Our intranet’s page header is in Helvetica Neue Light. Now that I’m using Firefox 3 again, I noticed it wasn’t rendering right; it was regular Helvetica. Firefox 3 has better font rendering, so I knew it’s supposed to be able to use it. Why didn’t it?

For it to show up in Safari, you have to put the typeface name and the variant in the font-family, and spell it a little weird, like so:

font-family: "HelveticaNeue-Light";

Some Googling says you can use Helvetica Neue Light in Firefox if you spell it out like a normal font name:

font-family: "Helvetica Neue Light";

I assume that works in Firefox 2, but it doesn’t seem to in Firefox 3. After enough banging on it, I found Firefox 3 (reasonably) wants you to specify the font in font-family and the weight variant the real CSS way, with font-weight:

font-family: "Helvetica Neue";
font-weight: 100;

So to cover all the bases, in practice you’d write:

font-family: "HelveticaNeue-Light", "Helvetica Neue Light",
             "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 100;

Firefox 3

Download DayKesh’s post reminds me: Firefox 3 comes out tomorrow, Tuesday the 17th—but I’ve already been using it. Despite overcoming the lack of Greasemonkey and Firebug, Safari still has no Awesomebar, and I can happily report that since upgrading to Firefox 3 rc2 (now rc3) and Firefox 3 versions of my extensions (Firebug, Greasemonkey, and Adblock Plus), I haven’t noticed any crashing, either.

  • That first link is about Spread Firefox’s Download Day 2008, the attempt to get Firefox into the Guinness World Record book for “most software downloads in 24 hours.”
  • Deb Richardson compiled a field guide to Firefox 3 showing off all the new features and improvements.
  • If you don’t want to read, watch Mike Beltzner’s screencast guide to the major features instead.
  • The improved default theme for OS X is more OS X-y, but if it’s not quite OS X-y enough for you with all the rounded buttons and whatnot, try one of the GrApple themes.
  • Lastly, feel for Mark Smith, who’s working at Mozilla, supporting all this craziness.

If you aren’t going to use Firefox 3, there’s still good news: even at $0, the market for browsers is competitive again. Safari is a better browser because of Firefox, and Firefox 3 is a better browser because of Safari. Here’s looking forward to a Safari 4 that makes me want to switch again! (But hopefully not too soon.)



Hmm, my test CommitBit install doesn’t have the right CSS at all. Am I missing something? I installed CommitBit from subversion with Jifty from CPAN, and it doesn’t look anything like Best Practical’s.

Jifty seems to do this weird CSS compilation thing so I can’t tell where the CSS is supposed to be coming from, either.

Update: yeah, Jesse’s suggestion to use the CPAN version of CommitBit works great. Thanks!


TAP in pyparsing

Paul McGuire, author of pyparsing, was nice enough to write up a TAP parser using it for comparison to my yeanpypa attempt. A few days earlier I had hacked up my own pyparsing version too, as pyparsing has a few features that seemed like it would make a more forgiving parser. Here’s the pyparsing version I wrote:

Read more...Collapse )

Some interesting features:

  • I used the pydoc and the examples instead of the actual manual, so I didn’t see setDefaultWhitespaceChars that Paul used. I had to use CharsNotIn('#\n') in description and (?s) in the directive regexp so the dot wouldn’t match the \n.
  • I used a parse action to strip the optional leading dash from description, rather than try to match it. Looking back now I don’t see why I couldn’t include the Optional('-') on the front, but it seemed to make sense when I wrote it.

Using Combine and the naming feature means I get immediately useful results with this parser, unlike the yeanpypa parser, which ends up being more of a tokenizer.

>>> from tap_parser import tap
>>> test1 = """\                                                                                                          
... 1..4                                                                                                                  
... ok 1 - Input file opened                                                                                              
... not ok 2 - First line of the input valid                                                                              
... ok 3 - Read the rest of the file                                                                                      
... not ok 4 - Summarized correctly # TODO Not written yet
... """
>>> res = tap.parseString(test1)
>>> res.plan
>>> res.tests[0].ok
>>> res.tests[1].ok
>>> res.tests[1].notok
'not ok'
>>> res.tests[1].description
'First line of the input valid'
>>> [res.tests[3][f] for f in ('num', 'todo', 'description')]
['4', 'todo', 'Summarized correctly ']

Paul still uses a function in his example to massage the results into output, but my results map almost exactly into the Django model objects I planned to make.

On the other hand, mine fails Paul’s test3 example, which is certainly proper TAP. Seems to not be handling post-planned results due to my attempted use of Each (the & operator). Hmm.

Update: Oh, no, it was the missing test numbers that made it barf. Somehow I’d read into the TAP spec that a test number was required if there was a description… or at least accidentally written that into the parser. Changing test_line’s definition thusly made the tests work (though I’m only testing one stream for correctness so far):

test_line = result + Optional(test_num) +
            Optional(description) + Optional(directive)



Fair's fair

Somehow I got onto WebKit nightlies instead of stable Safari 3, and even after uninstalling SIMBL and losing magic Greasemonkey powers, it’s crashy. Just so you know.

Previous 10 | Next 10