Using git for Backup is Asking for Pain
December 08, 2009 at 01:10 PM | Version control | View Commentsgit isn't a backup system.
Neither is Mercurial, Bazaar, Subversion or even (even) CVS CSV.
Version control systems, with the possible exception of SourceSafe, are great at keeping track of code. Why is that? Because they were designed to keep track of code.
Unfortunately, though, the features of a good VCS are entirely different – and often exactly the opposite – of the features which make a good backup system.
Take, for example, file ownership. A good VCS will, very rightly, ignore file ownership: when I check out someone else's code, I should be the owner of those file - not whatever uid
originally created them. A good backup system, on the other hand, will do everything in its power to preserve file ownership: when I restore from my backups, I want /etc/shaddow
to be owned by root
and /home/wolever/
to be owned by wolever
.
And ownership is just one example - permissions†, creation and modification times, empty directories‡, hardlinks, xattrs, resource forks, … the list of details that a backup system must keep track of goes on and on.
In fact, there are so many things a backup system can get wrong, there is a project called Backup Bouncer, designed specifically to verify that backup scripts correctly copy all the various bits of metadata tracked by the filesystem.
So, please: if you value your bytes, use a real backup system, not git.
†: Most VCSs only track the 'x' bit - for backup purposes, all bits, including suid bits, must be tracked.
‡: fun fact - Mercurial and git don't track empty directories, but Bazaar does.
(alternate title: The "Fail Early, Fail Often" Principle in Action)
I would like to award Adobe the "best ever implementation of indexOf
". Ready for it? Here it is:
override flash_proxy function callProperty(name:*, ... rest):* {
return null;
}
This beauty can be found in mx.collections.ListCollectionView
.
And the kicker? The function's documentation:
/**
* @private
* Any methods that can't be found on this class shouldn't be called,
* so return null
*/
The author clearly knew that unknown methods* shouldn't be called… But instead of doing something sensible – like throwing an exception – they do something wholly nonsensical and return null
. Or, of course, they could also have left the function unimplemented, which would result in a strange and unhelpful exception… But, of course, I would expect nothing but the best from the Flex standard library.
Next up: why implicit conversions from null
to int
are always wrong.
</rant>
*: the magic callProperty
method is called on subclasses of Proxy
when a method can't be found. For example if bar
is not a method of foo
, executing foo.bar()
will call foo.callProperty("bar")
.
PS: Instead of calling indexOf
, I should have been calling getItemIndex
.
You and Your Editor: Vim normal mode commands g, : and d (3 of N)
December 05, 2009 at 08:22 PM | Vim | View CommentsIn my last post, I showed off some normal-mode data from vim-logging. In this (and the next few) posts, I'll go though my most-used commands and describe how I use them.
(Don't use Vim? This post won't be too interesting… Although you may pick up something useful)
g
My logs contain more than 60,000 references to the 'g' command (eight times more than ':', the next most frequently used command). This may seem surprising at first, but stick with me and let me explain: the 'g' command is something of a 'gateway' command - a prefix for a number of common actions which don't have their own single-character command (for example, gd, goto definition and g?, rot13 encode).
Here is a breakdown of the 'g' suffixes I often use:
gj and gk: cursor to next row, cursor to previous row ("make
j
andk
do the right thing"). Thej
andk
commands are defined as "move to next line" and "move to previous line", not "move to next screen row" and "move to previous screen row". This is an important distinction to make when long lines are wrapped, and I find "move to next/previous screen row" is a more reasonable default. Protip: usenoremap j gj
andnoremap k gk
in yourvimrc
.gg: cursor to top of file. After using
gg
(for example, to edit some import statements or add a shebang line), I often use''
(tick-tick) to jump back to the line I was editing at the time (for example,ggofrom foo import bar<esc>''
). Also, I often useggVG
(go to top, enter line-visual-mode, go to bottom) to select the entire file. From there, I can pipe it to something (for example,:!sort
), format it (gw
) or copy it to the clipboard.gt and gT: go tab - move to next/previous tab.
gf: goto file - edit the file under the cursor. For example, if the cursor is over the 'e' in
import "../eventDispatercherImpl.as"
, the equivalent of:e ../eventDispatercherImpl.as
will be executed.gw: go wrap. Wrap the selected text (that is, text selected in visual mode). Try selecting a long line (pressing
V
), then usinggw
to wrap it.
That's all the 'g' commands I can think of for now... The next version of vim-logging will log the sub-command used, so I will be able to provide better data in the future.
:
The colon command is fairly obvious: enter command-line mode to run commands like :w
or :help :
.
I'll write more about this later, when I analyze my most-used ex commands.
d
Ah, d
- delete - the programmers best friend.
As with g
, I do not have detailed information about how I use d
, but I'll list the first few combinations that come to mind when I move my left index finger over the d
key:
dd
to delete whole linesdi(
to delete everything inside a pair of parenthesisedfx
to delete everything between the current position and the next occurrence of 'x'dj
anddk
to delete this and the next/previous lined$
to delete from the current position to the end of the lined
in visual mode to delete the selected text.
You and Your Editor: Data from vim-logging (2 of N)
December 05, 2009 at 07:19 PM | Vim | View CommentsRemember when I blogged about vim-logging? Well, I've finally gotten around to interpreting the results.
First, I will cover what I believe to be the most important thing to know about vim: the normal mode commands.
Below is a chart of my 39 (why 39? I can't remember - when I created the graph, that's the number I chose) most-frequently-used normal-mode commands:
(many - see discussion) | g |
|
(ex mode command) | : | |
(delete) | d | |
(find in line) | f | |
(move forward word) | w | |
(insert mode at beginning of line) | I | |
(change) | c | |
(move to beginning of line) | ^ | |
(insert mode at end of line) | A | |
(move back word) | b | |
(undo) | u | |
(move to next search match) | n | |
(search) | / | |
(move left) | h | |
(z[nm]): close/open folds, z[tbz]: scroll window) | z | |
(insert mode before character) | i | |
(move to end of line) | $ | |
(c_w-c_[wljh_] - window commands) | Ctrl_W | |
(insert mode after character) | a | |
(find backwards in line) | F | |
(insert node in next line) | o | |
(move cursor half screen down) | Ctrl_D | |
(move line down) | j | |
(move line up) | k | |
(enter normal mode) | ESC | |
(repeat previous find in line) | ; | |
(substitute character) | s | |
(delete character) | x | |
(put from register) | p | |
(delete line) | D | |
(}} - move to next blank line) | } | |
({{ - move to previous blank line) | { | |
(enter visual-line-mode) | V | |
(go to bottom of file) | G | |
(replace) | r | |
(visual mode) | v | |
(yank text) | y | |
(change line) | C | |
(insert mode on previous line) | O |
I'm sure you didn't notice, but I'll tell you about it anyway: the server that runs wolever.net and codekills.net, lazarus, died of unknown causes two weeks ago.
It took two weeks to get everything fixed because it lives in Toronto and I live in Waterloo… And the first weekend I went back to pick it up… I forgot to pick it up.
Right now the data has been migrated to another machine (the one you're talking to right now), and it is doubtful if lazarus will ever live again.