No such tree SHA1 was found

Piston is a utility that eases vendor branch management.
This is similar to svn:externals, except you have a local copy of
the files, which you can modify at will. As long as the changes are
mergeable, you should have no problems.

This tool has a similar purpose than svnmerge.py which you can find in the
contrib/client-side folder of the main Subversion repository at
http://svn.collab.net/repos/svn/trunk/contrib/client-side/svnmerge.py.
The main difference is that Piston is designed to work with remote
repositories. Another tool you might want to look at, SVK, which you can find
at http://svk.elixus.org/.

From Wikipedia’s Piston page (http://en.wikipedia.org/wiki/Piston):
In general, a piston is a sliding plug that fits closely inside the bore
of a cylinder.

Its purpose is either to change the volume enclosed by the cylinder, or
to exert a force on a fluid inside the cylinder.

For this utility, I retain the second meaning, “to exert a force on a fluid
inside the cylinder.” Piston forces the content of a remote repository
location back into our own.

= Installation

Nothing could be simpler:

$ gem install —include-dependencies piston

= Usage

First, you need to import the remote repository location:

$ piston import http://dev.rubyonrails.org/svn/rails/trunk vendor/rails
Exported r4720 from ‘http://dev.rubyonrails.org/svn/rails/trunk’ to ‘vendor/rails’

$ svn commit -m “Importing local copy of Rails”

When you want to get the latest changes from the remote repository location:

$ piston update vendor/rails
Updated ‘vendor/rails’ to r4720.

$ svn commit -m “Updates vendor/rails to the latest revision”

You can prevent a local Piston-managed folder from updating by using the
+lock+ subcommand:

$ piston lock vendor/rails
‘vendor/rails’ locked at r4720.

When you want to update again, you unlock:

$ piston unlock vendor/rails
‘vendor/rails’ unlocked.

If the branch you are following moves, you should use the switch subcommand:

$ piston import http://dev.rubyonrails.org/svn/rails/branches/1-2-pre-release vendor/rails
$ svn commit vendor/rails

# Vendor branch is renamed, let’s follow it
$ piston switch http://dev.rubyonrails.org/svn/rails/branches/1-2-stable vendor/rails

= Contributions

== Bash Shell Completion Script

Michael Schuerig contributed a Bash shell completion script. You should copy
+contrib/piston+ from your gem repository to the appropriate folder. Michael
said:

I've put together a bash completion function for piston. On Debian, I
just put it in /etc/bash_completion.d, alternatively, the contents can
be copied to ~/.bash_completion. I don’t know how things are organized
on other Unix/Linux systems.

= Caveats

== Speed

This tool is SLOW. The update process particularly so. I use a brute force
approach. Subversion cannot merge from remote repositories, so instead I
checkout the folder at the initial revision, and then run svn update and
parse the results of that to determine what changes have occured.

If a local copy of a file was changed, it’s changes will be merged back in.
If that introduces a conflict, Piston will not detect it. The commit will be
rejected by Subversion anyway.

== Copies / Renames

Piston does not track copies. Since Subversion does renames in two
phases (copy + delete), that is what Piston does.

== Local Operations Only

Piston only works if you have a working copy. It also never commits your
working copy directly. You are responsible for reviewing the changes and
applying any pending fixes.

== Remote Repository UUID

Piston caches the remote repository UUID, allowing it to know if the remote
repos is still the same. Piston refuses to work against a different
repository than the one we checked out from originally.

= Subversion Properties Used

  • piston:uuid: The remote repository’s UUID, which we always confirm
    before doing any operations.
  • piston:root: The repository root URL from which this Piston folder
    was exported from.
  • piston:remote-revision: The Last Changed Rev of the remote
    repository.
  • piston:local-revision: The Last Changed Rev of the Piston
    managed folder, to enable us to know if we need to do any merging.
  • piston:locked: The revision at which this folder is locked. If
    this property is set and non-blank, Piston will skip the folder with
    an appropriate message.

= Dependencies

Piston depends on the following libraries:

  • yaml
  • uri
  • fileutils