func crossReleaseChanges(cmd *c.Command, args []string) {
	dev.MustFindCrowbar()
	if len(args) != 2 {
		log.Fatalf("%s takes exactly 2 release names!")
	}
	releases := new([2]dev.Release)
	// Translate command line parameters.
	// releases[0] will be the release with changes, and
	// releases[1] will be the base release.
	for i, name := range args {
		switch name {
		case "current":
			releases[i] = dev.CurrentRelease()
		case "parent":
			if i == 0 {
				log.Fatalf("parent can only be the second arg to %s\n", cmd.Name())
			}
			releases[1] = releases[0].Parent()
			if releases[1] == nil {
				log.Fatalf("%s does not have a parent release.\n", releases[0].Name())
			}
		default:
			releases[i] = dev.GetRelease(name)
		}
	}
	dev.CrossReleaseChanges(releases[0], releases[1])
}
func showRelease(cmd *c.Command, args []string) {
	dev.MustFindCrowbar()
	if len(args) == 0 {
		dev.ShowRelease(dev.CurrentRelease())
	} else {
		for _, rel := range args {
			dev.ShowRelease(dev.GetRelease(rel))
		}
	}
}
func builds(cmd *c.Command, args []string) {
	dev.MustFindCrowbar()
	res := make([]string, 0, 20)
	if len(args) == 0 {
		for build := range dev.CurrentRelease().Builds() {
			res = append(res, dev.CurrentRelease().Name()+"/"+build)
		}
	} else {
		for _, release := range args {
			for build := range dev.GetRelease(release).Builds() {
				res = append(res, release+"/"+build)
			}
		}
	}
	sort.Strings(res)
	for _, build := range res {
		fmt.Println(build)
	}
}
func splitRelease(cmd *c.Command, args []string) {
	if len(args) != 1 {
		log.Fatalf("split-release only accepts one argument!")
	}
	dev.MustFindCrowbar()
	current := dev.CurrentRelease()
	if _, err := dev.SplitRelease(current, args[0]); err != nil {
		log.Println(err)
		log.Fatalf("Could not split new release %s from %s", args[0], current.Name())
	}
}
func remoteChanges(cmd *c.Command, args []string) {
	dev.MustFindCrowbar()
	switch len(args) {
	case 0:
		dev.RemoteChanges(dev.CurrentRelease())
	case 1:
		dev.RemoteChanges(dev.GetRelease(args[0]))
	default:
		log.Fatalf("%s takes 0 or 1 release name!\n", cmd.Name())
	}
}
func zapBuild(cmd *c.Command, args []string) {
	if len(args) != 1 {
		log.Fatalf("remove-build only accepts one argument!\n")
	}
	buildName := args[0]
	dev.MustFindCrowbar()
	if !strings.Contains(buildName, "/") {
		// We were passed what appears to be a raw build name.
		// Turn it into a real build by prepending the release name.
		buildName = dev.CurrentRelease().Name() + "/" + buildName
	}
	builds := dev.Builds()
	build, found := builds[buildName]
	if !found {
		log.Fatalf("%s is not a build, cannot delete it!", buildName)
	}
	if strings.HasSuffix(buildName, "/master") {
		log.Fatalf("Cannot delete the master build in a release!")
	}
	if err := build.Zap(); err != nil {
		log.Fatal(err)
	}
	log.Printf("Build %s deleted.\n", buildName)
}
func currentRelease(cmd *c.Command, args []string) {
	dev.MustFindCrowbar()
	fmt.Println(dev.CurrentRelease().Name())
}