Archive for the 'Subversion' Category

Quickie: Finding an svn conflict marker with vim

Tuesday, February 12th, 2008
/[<=>]\{7\}

Generating a tarball of your project

Friday, February 8th, 2008

Every good version-control system has this as a built-in feature.

In the below, $TMP is a staging directory, such as “build”, “/tmp”, or “/Volumes/RAM Disk”. It's also where the final archive will end up.

  • svn: Sort of. svn export $TMP/MyProject && cd $TMP && tar cjf MyProject.tbz MyProject
  • darcs: darcs dist (outputs a .tar.gz file in the current working directory)
  • bzr: bzr export --format=tbz2 $TMP/MyProject.tbz
  • git: git archive --format=tar master | bzip2 > $TMP/MyProject.tbz
  • hg: hg archive -p MyProject -t tbz2 $TMP/MyProject.tbz

From svn to darcs: Listing unknown files

Sunday, December 2nd, 2007

If you're an svn user looking at darcs, you may wonder how to find unknown files—that is, files that you've created in your working directory, but haven't yet told your VCS about (with svn add or darcs add). In svn, the command is svn st, but in darcs, the procedure is not obvious.

The darcs command that most seems like what you need is darcs whatsnew, or, as I type it, simply darcs what. Like svn st, this shows you all files that have been added, removed, or modified; it also includes a diff, so not only is it your substitute for svn st, it's also your substitute for svn diff. But it doesn't show you unknown files.

Until you use the -l (that's a lowercase L) option.

darcs what -l changes the output greatly, as it's in a completely different format: one similar to that of svn st. The format is actually that of darcs what -s (summary mode); the difference is that -l also lists unknown files.

There are some differences between darcs what -l and svn st. Some of these differences are:

  • darcs uses fewer columns than svn: It has one status column, whereas svn has six.
  • darcs uses ‘a’ to indicate an unknown file, whereas svn uses ‘?’.
  • darcs uses ‘R’ to indicate a file that you've removed, whereas svn uses ‘D’ to indicate a file that you've deleted. (svn supports remove and rm as synonyms for its delete command, but darcs does not support delete nor rm as synonyms for its remove command.)

What do different VCSs do when a file changes?

Thursday, October 11th, 2007

Here's the scenario:

  1. You change a file.
  2. You invoke your-vcs-here commit file.txt (or equivalent).
  3. You write a commit message in the editor.
  4. You suspend the editor with ^z and make another change to a file. (Perhaps you started the commit and a build at the same time, and the build failed because you forgot a comma.)
  5. You resume the editor, and issue :wq or ^x^c to save and exit.

What happens?

Subversion

svn commits the changed version of the file—in other words, the file as it existed when the editor exited.

Monotone

mtn notices that the file changed, tells you “you can't do that”, and throws away saves the commit message.

More precisely, it says:

mtn: misuse: file 'Test.txt' modified during commit, aborting

darcs

darcs commits the file as it existed before it started the editor. (Presumably, it copies changed files to a staging area rather than simply committing them from the WC.)

Mercurial

hg commits the file as it existed before it started the editor, just as darcs does.


UPDATE 2008-03-05: Jack, in a comment below, corrected me on what Monotone does with the commit message. I have applied this correction above.

UPDATE 2008-03-26: jpc, in a comment below, corrected me on what Mercurial does with the commit message. I thought that that's what I had written, but I wrote the wrong thing: that it acted like svn, rather than darcs. I apologize for the brainfart, and I have applied this correction above.

Quicksilver + SVN = yum

Friday, August 17th, 2007

Go directly to the plug-ins pane of your Quicksilver Preferences and install the Subversion module. Do not pass Go. Do not check out $200.

Best when combined with the comma trick.

So far, I've tried both add and ci, and they work in the obvious way. They even provide a notification (which goes through the Growl notifier for me—that's another plug-in) with the command's output.

Handy svn technique

Wednesday, November 29th, 2006

Easy way to create a repo and then immediately make your existing source code (foo) into a checkout:

  1. % svnadmin create foo_repo
  2. % mkdir foo_wc foo_wc/branches foo_wc/tags
  3. % mv foo foo_wc/trunk
  4. % svn co foo_repo foo_wc (Note that svn co requires a URL.)
  5. % cd foo_wc
  6. % svn add *
  7. % svn ci

Yes, that's right: This doesn't use svn import at all. svn import, in fact, is useless, since (a) it doesn't give you a WC you can then operate on (you have to check it out again), and (b) it doesn't let you do multiple things with the commit (e.g. create branches and tags directories at the top level of the repo; you would have to do a second commit).

How to apply changes in a framework to a versioned copy of it

Tuesday, November 14th, 2006

In Adium 1.0, we'll have a number of external frameworks:

So whenever any of these frameworks changes — especially if it fixes a bug that we've been suffering from — we build the framework in our copy of their source code, and then we drop the new built framework into our source repo and commit it.

But I often see it done this way:

  1. svn rm Foo.framework
  2. svn ci Foo.framework
  3. cp -R ../../Foo/build/Release/Foo.framework Foo.framework
  4. svn add Foo.framework
  5. svn ci Foo.framework

This is wrong, for three reasons:

  • Commit history for the framework is lost. svn doesn't relate the new framework to the old framework that previously occupied the same path.
  • Much space and bandwidth is wasted as all of the files in the framework (including nibs, images, plists) are copied yet again, even those that were not changed.
  • It takes two commits to do one job.

Here's a better way.

  1. pushd ../../Foo/build/Release
  2. tar cf Foo-framework.tar Foo.framework
  3. mv Foo-framework.tar $OLDPWD
  4. popd
  5. tar xf Foo-framework.tar && rm Foo-framework.tar
  6. svn ci Foo.framework

tar will overwrite every file in the framework, and of course any new ones will be created. A quick svn st will show you which files are new (unversioned) or modified; if there are any unversioned files, you should of course svn add them before committing. And then when you commit, the commit history of all the files is preserved, so you can do svn log (or the equivalent operation in Trac) later, and svn will apply its own smarts about exactly what should be copied.

The only downside to this approach is that any files that no longer exist in the old framework won't be removed. If you have reason to believe that any files were deleted, you should perform ls -R on both directories, diff -u the two results, and look for “-” lines. But most of the time, this isn't necessary; how often does anything ever get removed from a framework?

So, anyway, please use tar, for the sake of the commit history. ☺

UPDATE 11:55: If you want an example, here's Adium changeset number 18243, in which I did this to the LMX framework. See how small that changeset is?

UPDATE 14:08: Fixed SparklePlus link.

How to use svn merge

Sunday, October 29th, 2006

A number of my fellow Adium developers have observed that svn merge is hard to use. I think the main problem is that the command is quite general (it can be put to several different uses) and the documentation not particularly clear. In order to promote better understanding of the svn merge command, here's what I know about it.

The command in a nutshell: svn merge is essentially svn diff $ARGS | patch -p0; the only real difference is that svn merge will handle addition, movement, and deletion of files, whereas patch won't.

This now having been stated up front, let's get into details.

Summary of tasks and how to do them

  1. svn merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
  2. svn merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
  3. svn merge [-c M | -r N:M] SOURCE[@REV] [WCPATH]
  • To apply changes from another directory (branch, tag, trunk): Use format #1 (or #2 if you have a checkout of it), supplying at least the first revision (N), and the second (M) if it is not HEAD. With format #1, you should not need to be using the same repository URL as the CWD for either one or both; you should be able to merge between two URLs, or between a single URL into your checkout of a different URL.

  • To travel back in time to a previous revision: Use format #3, with -rHEAD:THEN. For example, -rHEAD:42000.

  • To cherry-pick a changeset (apply only that changeset, not any others): Use format #3, with -cTHEN.

  • To undo a particular changeset without disturbing things that happened after it (hopefully): Use format #3, with -c -THEN. Note the minus sign. For example, to revert r42000, use “svn merge -c -42000 .”. You can also use the -r flag: “svn merge -r 42000:41999 .”. This may be advisable, for clarity reasons, if you have a script that must always revert a particular revision.

    In both examples, note the “.” and the space before it. “.” means the current directory, and is used here as the SOURCE argument to format #3. It's a separate argument from the revision, so you need the space.

  • All formats apply their changes to the CWD by default. I don't know what happens if the CWD is not a WC. You can specify a different destination for the changes by specifying a different WCPATH (the last argument in all the formats above).

  • In format #3, the first path that it accepts is a URL or local WC path to the object you want to diff. (Remember my initial statement about svn merge being essentially svn diff | patch -p0.) The second path is a local WC path to the destination for the changes that are observed.

Updated 2007-07-12: Fixed error in traveling back in time (I had the revs backward); added cherry-picking technique.

svn help merge, in RTF

The “svn help merge” text is an invaluable summary of the command's operation, but it's plain-text, and therefore somewhat hard to read on a screen. To that end, I created an RTF version and printed it out, and decided to put it up here in case anyone else wants to do the same.