Sunday, May 19, 2013

Today's sermon touches on 1 Tim 4:11-6, where Paul exhorts Timothy to preach so that he might save both himself and his hearers. The question proposed in the sermon is how he can save anyone when we know that only God, only Christ Himself, can save us? The answer proffered is that we save by preaching the very Gospel that saves, that in a sense we do not save, but we provide the message that saves.

The challenge with this interpretation however is that the verse specifically says that we do in fact save, not merely that we are a conduit for salvation. God is certainly the one who works in us to save, but somehow Timothy is the direct agent to "save both yourself and your hearers." So how then do we as mere humans actually perform salvation? I think that the key is to ask ourselves, from what are we saved? In many cases the Scripture points to salvation from hell and sin, a very spiritual salvation that only God can enact in us. If I shared the Gospel to someone who then chose to follow Christ, I would never say that I saved him, but that Christ saved him.

We know however that there are many other things from which we can be saved. In this passage, Paul appears to refer less to eternal salvation and more to the practicalities of daily life and ministry. He speaks of the challenges of service and of preaching to guide people through the daily struggles of life. He may therefore be referring to the very power and responsibility we have to save people not only from walking into gross sin, but also from all the senseless trials, conflict, and even simple stupidity that we have all committed. Through the experiences that Timothy has suffered and the maturity that he has gained despite his youthfulness, he can share with them the strategies that he has gained and the Scriptures that he has learned to help save them from falling into the mistakes that he has committed himself or as a leader has seen others make.

By helping to "save both yourself and your hearers," we can also exemplify on a daily basis God's eternal salvation of us. By saving people from all sorts of practical, visible troubles that we might otherwise find ourselves in, we can more readily see and more deeply appreciate the internal and eternal salvation that only God has provided us in Christ.

Saturday, May 18, 2013

I recently migrated a Sourceforge-hosted Subversion repository to a Git repository for one of my open-source projects. I also have a number of private projects holed up on an old Linux server at home and decided that it's nigh time to git them over to Git as well. Now that I have a Mac Mini, I figured that I could take advantage of its Unix backbone to set up a simple SSH-based, self-hosted Git server.

My code will get an upgrade in hardware and version control protocol in one fell swoop. And given the number of minor tricks I had to find along the way, especially with the help of this tutorial, I figured that I'd document them here for posterity's sake.

Exporting the Subversion repository
I again used svn2git to export the Subversion repository to a local Git repository. In my case, I had a multi-project Subversion repo and wanted to export only one sub-project, so I used the "--no-minimize-url" flag. It also happened to be in slightly non-standard layout ("TxtflMobile" instead of "trunk"), which required me to explicitly set the trunk name. The authors flag was as outlined previously.

As the repo was private, I had to specify the username to access the repo. Strangely, the execution hung, and I realized that I was supposed to provide my password even though it didn't prompt me--that is, until after I provided my password and hit Enter.

To check the export, I ran the "git branch" and "git tag" commands to see the listing of all branches and tags.

Setting up the simple Git server
Looking through Git server options, I initially thought that I would need to download a variety of third-party server packages to set it up. A great many server packages do exist, including 8 outlined here and seemingly several popular packages that have since arisen. Fortunately, one of the easiest of these options is also one recommended in the Git book itself, the SSH-based server that allows access through basic SSH login.

To set up the remote repository on the server, I logged into the server (which happened to be the same computer to which I had exported the Subversion repo). In the System Preferences, I made sure that "Remote login" was enabled, which turns on sshd to allow SSH connections. I also wanted to change the sshd port, which involved editing the /System/Library/LaunchDaemons/ssh.plist file and making sure that my router forwarded this port to my server.

Now that the server was accessible (was, in fact, a "server"), I created a "bare" repository in the location from which I would host the Git repo and into which I would push my local Git repo.

In my case, I used my username and customized port (eg "123") for login. Note that the "ssh://" protocol is necessary to specify the alternate port. In the process of learning this trick, I had to edit the URL for "origin" by using the "set-url" parameter in place of "add". In this case, I used "127.0.0.1" as the IP because I would be pushing the local repo from same machine as the server.

Once I had set the remote URL, it was just a matter of pushing up the master branch, each additional branch, and all the tags to the server.

Accessing the repo from abroad
Of course, one of the main benefits of hosting the hosting the repo remotely is that one can access it from abroad. Using the "git clone" command to the server's URL allowed me to download it onto another machine.

Another benefit of hosting the repo remotely is for backups. The cloned copies each serve as backups, and the remote repo itself can be backed up from the server. As one still getting used to Git, I immediately made an erroneous commit that I had already pushed to the remote server. While reverting this change can be difficult once on the remote server, in this case I merely had to enter the Time Machine backup software and restore the folder on the remote machine from a preceding backup. This simple solution is of course much more feasible given the simplicity of the project on such a simple server.

Monday, May 06, 2013

I still remember when a friend at church came up to me and said, "I'm gonna tell 'bout something you're gonna love. It's called Subversion." At the time, CVS had been the main version control system for keeping track of files, and it had revolutionized my way of thinking about backups and record-keeping. But CVS had its limitations, including lack of basic functionality such as renaming files cleanly. Subversion was like "a breath of fresh air," where seemingly all of the limitations of CVS went "poof."

But alas, the world has moved on, and Git has grit its teeth deeply into the stronghold of Subversion. Having built so many projects with Subversion behind the scenes, I was rather reluctant to git over to Git. I knew it was only a matter of time, however, and finally decided that I must give it a shot, starting with one of the several Sourceforge projects I administer.

Sourceforge supports a number of version control systems, including both Subversion and Git. Surprisingly, the documentation for migrating a Subversion repository to Git on Sourceforge was rather sparse, and as far as I can see, there's no auto-migration mechanism to simplify the task. Fortunately, there are many other tools to simplify the process, which I'd like to document for posterity here.

The beauty of the migration is that it doesn't require downloading the whole Subversion repository. The tool svn2git can apparently work on the remote repository to do all the conversion, and then the resulting local Git repository can be pushed onto the Sourceforge-hosted remote Git repo.

On my Mac, I first made sure that git, git-svn, ruby, and rubygems were installed. All the packages must have come with XCode Developer Tools as they were all already installed and ready to go. I next installed svn2git using the simple command:

$ sudo gem install svn2git

I then created a new directory to hold the new repository and entered it:

$ mkdir jaj$ cd jaj

The simplest command for import, which assumes the standard trunk/tags/branches layout, would have been (for my "jarajar" project with mountpoint "code"):

$ svn2git https://svn.code.sf.net/p/jarajar/code

To map the author names to Sourceforge email addresses, I made a simple authors.txt file of the format:

GitHub recommends import of each project within a Subversion repository to a separate Git repo. In my case, my Subversion repo was laid out for multiple projects, even though it really only contained one. To import only this project, I pointed svn2git to this project folder alone and passed the "--rootistrunk" argument:

Note that in the process of experimenting, I had failed imports that kept on failing, even though the subsequent commands were correct as far as I could tell. It turns out that the import process created a .git folder that had become corrupted and was preventing subsequent exports, even with the correct command. Deleting the .git file fixed these errors to start afresh, and running the commands with the "--verbose" command greatly simplifying troubleshooting.

Once I had imported the repository into my new local Git repo, I simply needed to push it to the Sourceforge-hosted Git repo. After creating an empty Git repo using the Sourceforge project Admin tool, I followed the Sourceforge import instructions for pushing a local repository (conducted from within the same directory):

And voila, my Subversion repository popped up in my Git repo, including all historical dates from revisions of old. Had I imported the entire project, maybe I would even see that venerable commit message, "New repository initialized by csv2svn." And back then, that had to be done by a Sourceforge engineer.

Notable Quotable

"This club with a shortage of ego and an excess of character ascended to baseball's throne in the way it preferred, with a collaborative performance." (Chris Haft, on the San Francisco Giants' 2012 World Series victory)

"In a society that craves results now, in a world that demands excellence every day, head coaches rarely are allowed the time they need to grow into the job and master it. Reminders of it come every year at this time. Head coaches are fired, head coaches are hired and the coaching carousel spins without producing in the ways NFL owners had hoped." (Adam Shefter, on the "coaching carousel" of rapid coaching firing/hiring after the season)

"A perennial danger among contemporary students of the New Testament is to overlook the two-thousand-year history of debate and interpretation generated by these twenty-seven books. The pressure to be up-to-date with the voluminous contemporary literature, combined with the penchant endemic to twenty-first-century Western culture to revere the innovative, even the faddish, and be suspicious of the traditional, conspires to blind us to our connections with twenty centuries of Christian readers." (Carson DA & Moo DJ, An Introduction to the New Testament, p. 31)