diff --git a/.gitignore b/.gitignore
index 3f1c658b5740a24005b0d3f7fffef9d7e493bae9..4613d316ad555a89d9d338f74be87c732d22fdb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,8 @@
+.DS_Store
 .coverage/
+.vimrc
+_dist/
+_proto/*.pb.go
 bin/
 rootfs/tiller
 vendor/
-_proto/*.pb.go
-.vimrc
-.DS_Store
diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto
index 95f926430e32f24cb9ed5a7dd3ecab0620a6e310..ba3252e3ca86e725a3fe57c33db537b1396d72c7 100644
--- a/_proto/hapi/services/tiller.proto
+++ b/_proto/hapi/services/tiller.proto
@@ -162,6 +162,9 @@ message UpdateReleaseRequest {
 	hapi.chart.Config values = 3;
 	// dry_run, if true, will run through the release logic, but neither create
 	bool dry_run = 4;
+
+	// DisableHooks causes the server to skip running any hooks for the upgrade.
+	bool disable_hooks = 5;
 }
 
 // UpdateReleaseResponse is the response to an update request.
diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go
index c47a13e6a6f23af6ce618b8c09aff3a21aaa48cc..ad104926758942ad07e583736cac4170329d2095 100644
--- a/cmd/helm/helm.go
+++ b/cmd/helm/helm.go
@@ -84,12 +84,13 @@ func newRootCmd(out io.Writer) *cobra.Command {
 
 	cmd.AddCommand(
 		newCreateCmd(out),
+		newDeleteCmd(nil, out),
 		newGetCmd(nil, out),
+		newInitCmd(out),
+		newInspectCmd(nil, out),
+		newInstallCmd(nil, out),
 		newListCmd(nil, out),
 		newStatusCmd(nil, out),
-		newInstallCmd(nil, out),
-		newDeleteCmd(nil, out),
-		newInspectCmd(nil, out),
 		newUpgradeCmd(nil, out),
 	)
 	return cmd
diff --git a/cmd/helm/init.go b/cmd/helm/init.go
index 565022a89e8639ef853414caaddd470e3098246a..21852729554e356769c9f6199cc25ae4a15a06f8 100644
--- a/cmd/helm/init.go
+++ b/cmd/helm/init.go
@@ -19,6 +19,7 @@ package main
 import (
 	"errors"
 	"fmt"
+	"io"
 	"os"
 
 	"github.com/spf13/cobra"
@@ -32,58 +33,54 @@ Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.he
 `
 
 var (
-	tillerImg            string
-	clientOnly           bool
 	defaultRepository    = "kubernetes-charts"
 	defaultRepositoryURL = "http://storage.googleapis.com/kubernetes-charts"
 )
 
-func init() {
-	f := initCmd.Flags()
-	f.StringVarP(&tillerImg, "tiller-image", "i", "", "override tiller image")
-	f.BoolVarP(&clientOnly, "client-only", "c", false, "If set does not install tiller")
-	RootCommand.AddCommand(initCmd)
+type initCmd struct {
+	image      string
+	clientOnly bool
+	out        io.Writer
 }
 
-var initCmd = &cobra.Command{
-	Use:   "init",
-	Short: "initialize Helm on both client and server",
-	Long:  initDesc,
-	RunE:  runInit,
+func newInitCmd(out io.Writer) *cobra.Command {
+	i := &initCmd{
+		out: out,
+	}
+	cmd := &cobra.Command{
+		Use:   "init",
+		Short: "initialize Helm on both client and server",
+		Long:  initDesc,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if len(args) != 0 {
+				return errors.New("This command does not accept arguments")
+			}
+			return i.run()
+		},
+	}
+	cmd.Flags().StringVarP(&i.image, "tiller-image", "i", "", "override tiller image")
+	cmd.Flags().BoolVarP(&i.clientOnly, "client-only", "c", false, "If set does not install tiller")
+	return cmd
 }
 
 // runInit initializes local config and installs tiller to Kubernetes Cluster
-func runInit(cmd *cobra.Command, args []string) error {
-	if len(args) != 0 {
-		return errors.New("This command does not accept arguments. \n")
-	}
-
+func (i *initCmd) run() error {
 	if err := ensureHome(); err != nil {
 		return err
 	}
 
-	if !clientOnly {
-		if err := installTiller(); err != nil {
-			return err
+	if !i.clientOnly {
+		if err := client.Install(tillerNamespace, i.image, flagDebug); err != nil {
+			return fmt.Errorf("error installing: %s", err)
 		}
+		fmt.Fprintln(i.out, "\nTiller (the helm server side component) has been installed into your Kubernetes Cluster.")
 	} else {
-		fmt.Println("Not installing tiller due to 'client-only' flag having been set")
+		fmt.Fprintln(i.out, "Not installing tiller due to 'client-only' flag having been set")
 	}
-
-	fmt.Println("Happy Helming!")
-	return nil
-}
-
-func installTiller() error {
-	if err := client.Install(tillerNamespace, tillerImg, flagDebug); err != nil {
-		return fmt.Errorf("error installing: %s", err)
-	}
-	fmt.Println("\nTiller (the helm server side component) has been installed into your Kubernetes Cluster.")
-
+	fmt.Fprintln(i.out, "Happy Helming!")
 	return nil
 }
 
-// requireHome checks to see if $HELM_HOME exists, and returns an error if it does not.
 func requireHome() error {
 	dirs := []string{homePath(), repositoryDirectory(), cacheDirectory(), localRepoDirectory()}
 	for _, d := range dirs {
diff --git a/cmd/helm/inspect.go b/cmd/helm/inspect.go
index 2e43f0e7aeaf93b88541e75641a1b97094f51094..8d9948b6f772766a469641ed89cfe2c22a794634 100644
--- a/cmd/helm/inspect.go
+++ b/cmd/helm/inspect.go
@@ -130,11 +130,10 @@ func (i *inspectCmd) run() error {
 		fmt.Fprintln(i.out, string(cf))
 	}
 
-	if i.output == both {
-		fmt.Fprintln(i.out, "---")
-	}
-
-	if i.output == valuesOnly || i.output == both {
+	if (i.output == valuesOnly || i.output == both) && chrt.Values != nil {
+		if i.output == both {
+			fmt.Fprintln(i.out, "---")
+		}
 		fmt.Fprintln(i.out, chrt.Values.Raw)
 	}
 
diff --git a/cmd/helm/inspect_test.go b/cmd/helm/inspect_test.go
index 24c4a895e26520ac48793f6fc32185b0a2d62357..bbd9c61998bfc23080d9a4c9dbd71dc0d7d8de4f 100644
--- a/cmd/helm/inspect_test.go
+++ b/cmd/helm/inspect_test.go
@@ -61,4 +61,17 @@ func TestInspect(t *testing.T) {
 			t.Errorf("Expected\n%q\nGot\n%q\n", expect[i], got)
 		}
 	}
+
+	// Regression tests for missing values. See issue #1024.
+	b.Reset()
+	insp = &inspectCmd{
+		chartpath: "testdata/testcharts/novals",
+		output:    "values",
+		out:       b,
+	}
+	insp.run()
+	if b.Len() != 0 {
+		t.Errorf("expected empty values buffer, got %q", b.String())
+	}
+
 }
diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index e80527b48949860d1580c201624a88d9fdd9cfcc..b526ea090c6dd132094efa5d0d0e1d0873a217ae 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -17,6 +17,7 @@ limitations under the License.
 package main
 
 import (
+	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -24,6 +25,9 @@ import (
 	"path/filepath"
 	"strings"
 
+	"text/template"
+
+	"github.com/Masterminds/sprig"
 	"github.com/ghodss/yaml"
 	"github.com/spf13/cobra"
 
@@ -59,10 +63,11 @@ type installCmd struct {
 	chartPath    string
 	dryRun       bool
 	disableHooks bool
-	reuseName    bool
+	replace      bool
 	out          io.Writer
 	client       helm.Interface
 	values       *values
+	nameTemplate string
 }
 
 func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
@@ -98,8 +103,9 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
 	f.StringVar(&inst.namespace, "namespace", "default", "the namespace to install the release into")
 	f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install")
 	f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install")
-	f.BoolVar(&inst.reuseName, "reuse-name", false, "force Tiller to re-use the given name, even if that name is already used. This is unsafe in production")
+	f.BoolVar(&inst.replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production")
 	f.Var(inst.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2")
+	f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release")
 	return cmd
 }
 
@@ -113,13 +119,23 @@ func (i *installCmd) run() error {
 		return err
 	}
 
+	// If template is specified, try to run the template.
+	if i.nameTemplate != "" {
+		i.name, err = generateName(i.nameTemplate)
+		if err != nil {
+			return err
+		}
+		// Print the final name so the user knows what the final name of the release is.
+		fmt.Printf("final name: %s\n", i.name)
+	}
+
 	res, err := i.client.InstallRelease(
 		i.chartPath,
 		i.namespace,
 		helm.ValueOverrides(rawVals),
 		helm.ReleaseName(i.name),
 		helm.InstallDryRun(i.dryRun),
-		helm.InstallReuseName(i.reuseName),
+		helm.InstallReuseName(i.replace),
 		helm.InstallDisableHooks(i.disableHooks))
 	if err != nil {
 		return prettyError(err)
@@ -249,3 +265,16 @@ func locateChartPath(name string) (string, error) {
 
 	return name, fmt.Errorf("file %q not found", origname)
 }
+
+func generateName(nameTemplate string) (string, error) {
+	t, err := template.New("name-template").Funcs(sprig.TxtFuncMap()).Parse(nameTemplate)
+	if err != nil {
+		return "", err
+	}
+	var b bytes.Buffer
+	err = t.Execute(&b, nil)
+	if err != nil {
+		return "", err
+	}
+	return b.String(), nil
+}
diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go
index 41663a337c8a52e4979eae336d7f0c82a755b133..7043eee6d1fc559eb3add6478802e9b4e8b0e7dc 100644
--- a/cmd/helm/install_test.go
+++ b/cmd/helm/install_test.go
@@ -19,6 +19,7 @@ package main
 import (
 	"fmt"
 	"io"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -59,12 +60,20 @@ func TestInstall(t *testing.T) {
 		},
 		// Install, re-use name
 		{
-			name:     "install and reuse name",
+			name:     "install and replace release",
 			args:     []string{"testdata/testcharts/alpine"},
-			flags:    strings.Split("--name aeneas --reuse-name", " "),
+			flags:    strings.Split("--name aeneas --replace", " "),
 			expected: "aeneas",
 			resp:     releaseMock(&releaseOptions{name: "aeneas"}),
 		},
+		// Install, using the name-template
+		{
+			name:     "install with name-template",
+			args:     []string{"testdata/testcharts/alpine"},
+			flags:    []string{"--name-template", "{{upper \"foobar\"}}"},
+			expected: "FOOBAR",
+			resp:     releaseMock(&releaseOptions{name: "FOOBAR"}),
+		},
 	}
 
 	runReleaseCases(t, tests, func(c *fakeReleaseClient, out io.Writer) *cobra.Command {
@@ -113,3 +122,78 @@ sailor: sinbad
 		t.Errorf("Expected String() to be \n%s\nGot\n%s\n", y, out)
 	}
 }
+
+type nameTemplateTestCase struct {
+	tpl              string
+	expected         string
+	expectedErrorStr string
+}
+
+func TestNameTemplate(t *testing.T) {
+	testCases := []nameTemplateTestCase{
+		// Just a straight up nop please
+		{
+			tpl:              "foobar",
+			expected:         "foobar",
+			expectedErrorStr: "",
+		},
+		// Random numbers at the end for fun & profit
+		{
+			tpl:              "foobar-{{randNumeric 6}}",
+			expected:         "foobar-[0-9]{6}$",
+			expectedErrorStr: "",
+		},
+		// Random numbers in the middle for fun & profit
+		{
+			tpl:              "foobar-{{randNumeric 4}}-baz",
+			expected:         "foobar-[0-9]{4}-baz$",
+			expectedErrorStr: "",
+		},
+		// No such function
+		{
+			tpl:              "foobar-{{randInt}}",
+			expected:         "",
+			expectedErrorStr: "function \"randInt\" not defined",
+		},
+		// Invalid template
+		{
+			tpl:              "foobar-{{",
+			expected:         "",
+			expectedErrorStr: "unexpected unclosed action",
+		},
+	}
+
+	for _, tc := range testCases {
+
+		n, err := generateName(tc.tpl)
+		if err != nil {
+			if tc.expectedErrorStr == "" {
+				t.Errorf("Was not expecting error, but got: %v", err)
+				continue
+			}
+			re, compErr := regexp.Compile(tc.expectedErrorStr)
+			if compErr != nil {
+				t.Errorf("Expected error string failed to compile: %v", compErr)
+				continue
+			}
+			if !re.MatchString(err.Error()) {
+				t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err)
+				continue
+			}
+		}
+		if err == nil && tc.expectedErrorStr != "" {
+			t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr)
+		}
+
+		if tc.expected != "" {
+			re, err := regexp.Compile(tc.expected)
+			if err != nil {
+				t.Errorf("Expected string failed to compile: %v", err)
+				continue
+			}
+			if !re.MatchString(n) {
+				t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n)
+			}
+		}
+	}
+}
diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go
index d3e496cdab41a3534da2a99686c37e53719961a3..75a0f30828d9916eeb6bd8d1747b5f1dbce07299 100644
--- a/cmd/helm/lint.go
+++ b/cmd/helm/lint.go
@@ -47,7 +47,10 @@ var lintCommand = &cobra.Command{
 	RunE:  lintCmd,
 }
 
+var flagStrict bool
+
 func init() {
+	lintCommand.Flags().BoolVarP(&flagStrict, "strict", "", false, "fail on lint warnings")
 	RootCommand.AddCommand(lintCommand)
 }
 
@@ -59,6 +62,13 @@ func lintCmd(cmd *cobra.Command, args []string) error {
 		paths = args
 	}
 
+	var lowestTolerance int
+	if flagStrict {
+		lowestTolerance = support.WarningSev
+	} else {
+		lowestTolerance = support.ErrorSev
+	}
+
 	var total int
 	var failures int
 	for _, path := range paths {
@@ -77,7 +87,7 @@ func lintCmd(cmd *cobra.Command, args []string) error {
 			}
 
 			total = total + 1
-			if linter.HighestSeverity >= support.ErrorSev {
+			if linter.HighestSeverity >= lowestTolerance {
 				failures = failures + 1
 			}
 		}
diff --git a/cmd/helm/serve.go b/cmd/helm/serve.go
index ae60833abae6444fea95bb0fd8cf34e478ff9398..3fca0bd8aa1d4120d8b8b8e81ea90dcce17b2420 100644
--- a/cmd/helm/serve.go
+++ b/cmd/helm/serve.go
@@ -17,17 +17,19 @@ limitations under the License.
 package main
 
 import (
+	"os"
+	"path/filepath"
+
 	"github.com/spf13/cobra"
 
 	"k8s.io/helm/pkg/repo"
 )
 
-var serveDesc = `This command starts a local chart repository server that serves the charts saved in your $HELM_HOME/local/ directory.`
-
-//TODO: add repoPath flag to be passed in in case you want
-//  to serve charts from a different local dir
+var serveDesc = `This command starts a local chart repository server that serves charts from a local directory.`
+var repoPath string
 
 func init() {
+	serveCmd.Flags().StringVar(&repoPath, "repo-path", localRepoDirectory(), "The local directory path from which to serve charts.")
 	RootCommand.AddCommand(serveCmd)
 }
 
@@ -35,9 +37,19 @@ var serveCmd = &cobra.Command{
 	Use:   "serve",
 	Short: "start a local http web server",
 	Long:  serveDesc,
-	Run:   serve,
+	RunE:  serve,
 }
 
-func serve(cmd *cobra.Command, args []string) {
-	repo.StartLocalRepo(localRepoDirectory())
+func serve(cmd *cobra.Command, args []string) error {
+
+	repoPath, err := filepath.Abs(repoPath)
+	if err != nil {
+		return err
+	}
+	if _, err := os.Stat(repoPath); os.IsNotExist(err) {
+		return err
+	}
+
+	repo.StartLocalRepo(repoPath)
+	return nil
 }
diff --git a/cmd/helm/testdata/testcharts/novals/Chart.yaml b/cmd/helm/testdata/testcharts/novals/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ce1a81da67927f021934d269ef9a6b9c186d16fd
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/novals/Chart.yaml
@@ -0,0 +1,6 @@
+description: Deploy a basic Alpine Linux pod
+home: https://k8s.io/helm
+name: novals
+sources:
+- https://github.com/kubernetes/helm
+version: 0.2.0
diff --git a/cmd/helm/testdata/testcharts/novals/README.md b/cmd/helm/testdata/testcharts/novals/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3c32de5db6abcf366c2f162edcf822e7e1eb5e5b
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/novals/README.md
@@ -0,0 +1,13 @@
+#Alpine: A simple Helm chart
+
+Run a single pod of Alpine Linux.
+
+This example was generated using the command `helm create alpine`.
+
+The `templates/` directory contains a very simple pod resource with a
+couple of parameters.
+
+The `values.yaml` file contains the default values for the
+`alpine-pod.yaml` template.
+
+You can install this example using `helm install docs/examples/alpine`.
diff --git a/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c15ab8efc0fe5c15b931ef97f52540fbfa2b623f
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml
@@ -0,0 +1,26 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{.Release.Name}}-{{.Values.Name}}"
+  labels:
+    # The "heritage" label is used to track which tool deployed a given chart.
+    # It is useful for admins who want to see what releases a particular tool
+    # is responsible for.
+    heritage: {{.Release.Service | quote }}
+    # The "release" convention makes it easy to tie a release to all of the
+    # Kubernetes resources that were created as part of that release.
+    release: {{.Release.Name | quote }}
+    # This makes it easy to audit chart usage.
+    chart: "{{.Chart.Name}}-{{.Chart.Version}}"
+  annotations:
+    "helm.sh/created": {{.Release.Time.Seconds | quote }}
+spec:
+  # This shows how to use a simple value. This will look for a passed-in value
+  # called restartPolicy. If it is not found, it will use the default value.
+  # {{default "Never" .restartPolicy}} is a slightly optimized version of the
+  # more conventional syntax: {{.restartPolicy | default "Never"}}
+  restartPolicy: {{default "Never" .Values.restartPolicy}}
+  containers:
+  - name: waiter
+    image: "alpine:3.3"
+    command: ["/bin/sleep","9000"]
diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go
index c4f75310ffd43b69401d13def448dfe0becfb9fe..07eeae03b559633b5df13181d21480c07a536c63 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -34,12 +34,13 @@ argument can be a relative path to a packaged or unpackaged chart.
 `
 
 type upgradeCmd struct {
-	release    string
-	chart      string
-	out        io.Writer
-	client     helm.Interface
-	dryRun     bool
-	valuesFile string
+	release      string
+	chart        string
+	out          io.Writer
+	client       helm.Interface
+	dryRun       bool
+	disableHooks bool
+	valuesFile   string
 }
 
 func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
@@ -70,6 +71,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
 	f := cmd.Flags()
 	f.StringVarP(&upgrade.valuesFile, "values", "f", "", "path to a values YAML file")
 	f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade")
+	f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks")
 
 	return cmd
 }
@@ -88,12 +90,13 @@ func (u *upgradeCmd) run() error {
 		}
 	}
 
-	_, err = u.client.UpdateRelease(u.release, chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun))
+	_, err = u.client.UpdateRelease(u.release, chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun), helm.UpgradeDisableHooks(u.disableHooks))
 	if err != nil {
 		return prettyError(err)
 	}
 
-	fmt.Fprintf(u.out, "It's not you. It's me\nYour upgrade looks valid but this command is still under active development.\nHang tight.\n")
+	success := u.release + " has been upgraded. Happy Helming!\n"
+	fmt.Fprintf(u.out, success)
 
 	return nil
 
diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go
index 341670cd860fa98b5096b1b5660f8f9d4b39d974..f51049e28388220ff9455cdda40188f6e62070e5 100644
--- a/cmd/helm/upgrade_test.go
+++ b/cmd/helm/upgrade_test.go
@@ -52,18 +52,22 @@ func TestUpgradeCmd(t *testing.T) {
 		Description: "A Helm chart for Kubernetes",
 		Version:     "0.1.2",
 	}
+
 	chartPath, err = chartutil.Create(cfile, tmpChart)
 	if err != nil {
 		t.Errorf("Error creating chart: %v", err)
 	}
-	ch, _ = chartutil.Load(chartPath)
+	ch, err = chartutil.Load(chartPath)
+	if err != nil {
+		t.Errorf("Error loading updated chart: %v", err)
+	}
 
 	tests := []releaseCase{
 		{
 			name:     "upgrade a release",
 			args:     []string{"funny-bunny", chartPath},
 			resp:     releaseMock(&releaseOptions{name: "funny-bunny", version: 2, chart: ch}),
-			expected: "It's not you. It's me\nYour upgrade looks valid but this command is still under active development.\nHang tight.\n",
+			expected: "funny-bunny has been upgraded. Happy Helming!\n",
 		},
 	}
 
diff --git a/cmd/tiller/environment/environment.go b/cmd/tiller/environment/environment.go
index c40e37a73454621b6fe1b897ff023532e89e4483..7957b4224a190297a4c12d4047fa5f9f87dfd884 100644
--- a/cmd/tiller/environment/environment.go
+++ b/cmd/tiller/environment/environment.go
@@ -117,6 +117,15 @@ type KubeClient interface {
 	// For all other kinds, it means the kind was created or modified without
 	// error.
 	WatchUntilReady(namespace string, reader io.Reader) error
+
+	// Update updates one or more resources or creates the resource
+	// if it doesn't exist
+	//
+	// namespace must contain a valid existing namespace
+	//
+	// reader must contain a YAML stream (one or more YAML documents separated
+	// by "\n---\n").
+	Update(namespace string, originalReader, modifiedReader io.Reader) error
 }
 
 // PrintingKubeClient implements KubeClient, but simply prints the reader to
@@ -145,6 +154,12 @@ func (p *PrintingKubeClient) WatchUntilReady(ns string, r io.Reader) error {
 	return err
 }
 
+// Update implements KubeClient Update.
+func (p *PrintingKubeClient) Update(ns string, currentReader, modifiedReader io.Reader) error {
+	_, err := io.Copy(p.Out, modifiedReader)
+	return err
+}
+
 // Environment provides the context for executing a client request.
 //
 // All services in a context are concurrency safe.
diff --git a/cmd/tiller/environment/environment_test.go b/cmd/tiller/environment/environment_test.go
index 98af40edeb608bf0c3185f427b4bd14e752b8a2b..690587f324afc0e28f1937772f0a1af8b1ad24e9 100644
--- a/cmd/tiller/environment/environment_test.go
+++ b/cmd/tiller/environment/environment_test.go
@@ -87,6 +87,9 @@ func (k *mockKubeClient) Create(ns string, r io.Reader) error {
 func (k *mockKubeClient) Delete(ns string, r io.Reader) error {
 	return nil
 }
+func (k *mockKubeClient) Update(ns string, currentReader, modifiedReader io.Reader) error {
+	return nil
+}
 func (k *mockKubeClient) WatchUntilReady(ns string, r io.Reader) error {
 	return nil
 }
diff --git a/cmd/tiller/release_server.go b/cmd/tiller/release_server.go
index 0431b832d475aae96e45dbb7bdfc8a7dedb5fac8..7a4dab3dedc6cad976facd76d5048310d86a6b43 100644
--- a/cmd/tiller/release_server.go
+++ b/cmd/tiller/release_server.go
@@ -24,7 +24,6 @@ import (
 	"regexp"
 	"sort"
 
-	"github.com/Masterminds/semver"
 	"github.com/ghodss/yaml"
 	"github.com/technosophos/moniker"
 	ctx "golang.org/x/net/context"
@@ -171,65 +170,107 @@ func (s *releaseServer) GetReleaseContent(c ctx.Context, req *services.GetReleas
 }
 
 func (s *releaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
-	rel, err := s.prepareUpdate(req)
+	currentRelease, updatedRelease, err := s.prepareUpdate(req)
 	if err != nil {
 		return nil, err
 	}
 
-	// TODO: perform update
+	res, err := s.performUpdate(currentRelease, updatedRelease, req)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := s.env.Releases.Update(updatedRelease); err != nil {
+		return nil, err
+	}
+
+	return res, nil
+}
+
+func (s *releaseServer) performUpdate(originalRelease, updatedRelease *release.Release, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
+	res := &services.UpdateReleaseResponse{Release: updatedRelease}
+
+	if req.DryRun {
+		log.Printf("Dry run for %s", updatedRelease.Name)
+		return res, nil
+	}
+
+	// pre-ugrade hooks
+	if !req.DisableHooks {
+		if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, preUpgrade); err != nil {
+			return res, err
+		}
+	}
+
+	kubeCli := s.env.KubeClient
+	original := bytes.NewBufferString(originalRelease.Manifest)
+	modified := bytes.NewBufferString(updatedRelease.Manifest)
+	if err := kubeCli.Update(updatedRelease.Namespace, original, modified); err != nil {
+		return nil, fmt.Errorf("Update of %s failed: %s", updatedRelease.Name, err)
+	}
+
+	// post-upgrade hooks
+	if !req.DisableHooks {
+		if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, postUpgrade); err != nil {
+			return res, err
+		}
+	}
 
-	return &services.UpdateReleaseResponse{Release: rel}, nil
+	updatedRelease.Info.Status.Code = release.Status_DEPLOYED
+
+	return res, nil
 }
 
-// prepareUpdate builds a release for an update operation.
-func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, error) {
+// prepareUpdate builds an updated release for an update operation.
+func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) {
 	if req.Name == "" {
-		return nil, errMissingRelease
+		return nil, nil, errMissingRelease
 	}
 
 	if req.Chart == nil {
-		return nil, errMissingChart
+		return nil, nil, errMissingChart
 	}
 
 	// finds the non-deleted release with the given name
-	rel, err := s.env.Releases.Get(req.Name)
+	currentRelease, err := s.env.Releases.Get(req.Name)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	//validate chart name is same as previous release
-	givenChart := req.Chart.Metadata.Name
-	releasedChart := rel.Chart.Metadata.Name
-	if givenChart != releasedChart {
-		return nil, fmt.Errorf("Given chart, %s, does not match chart originally released, %s", givenChart, releasedChart)
+	ts := timeconv.Now()
+	options := chartutil.ReleaseOptions{
+		Name:      req.Name,
+		Time:      ts,
+		Namespace: currentRelease.Namespace,
 	}
 
-	// validate new chart version is higher than old
-
-	givenChartVersion := req.Chart.Metadata.Version
-	releasedChartVersion := rel.Chart.Metadata.Version
-	c, err := semver.NewConstraint("> " + releasedChartVersion)
+	valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	v, err := semver.NewVersion(givenChartVersion)
+	hooks, manifestDoc, err := s.renderResources(req.Chart, valuesToRender)
 	if err != nil {
-		return nil, err
-	}
-
-	if a := c.Check(v); !a {
-		return nil, fmt.Errorf("Given chart (%s-%v) must be a higher version than released chart (%s-%v)", givenChart, givenChartVersion, releasedChart, releasedChartVersion)
+		return nil, nil, err
 	}
 
 	// Store an updated release.
 	updatedRelease := &release.Release{
-		Name:    req.Name,
-		Chart:   req.Chart,
-		Config:  req.Values,
-		Version: rel.Version + 1,
+		Name:      req.Name,
+		Namespace: currentRelease.Namespace,
+		Chart:     req.Chart,
+		Config:    req.Values,
+		Info: &release.Info{
+			FirstDeployed: currentRelease.Info.FirstDeployed,
+			LastDeployed:  ts,
+			Status:        &release.Status{Code: release.Status_UNKNOWN},
+		},
+		Version:  currentRelease.Version + 1,
+		Manifest: manifestDoc.String(),
+		Hooks:    hooks,
 	}
-	return updatedRelease, nil
+
+	return currentRelease, updatedRelease, nil
 }
 
 func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
@@ -240,10 +281,12 @@ func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
 	if start != "" {
 		if rel, err := s.env.Releases.Get(start); err == driver.ErrReleaseNotFound {
 			return start, nil
-		} else if reuse && rel.Info.Status.Code == release.Status_DELETED {
+		} else if st := rel.Info.Status.Code; reuse && (st == release.Status_DELETED || st == release.Status_FAILED) {
 			// Allowe re-use of names if the previous release is marked deleted.
 			log.Printf("reusing name %q", start)
 			return start, nil
+		} else if reuse {
+			return "", errors.New("cannot re-use a name that is still in use")
 		}
 
 		return "", fmt.Errorf("a release named %q already exists", start)
@@ -306,12 +349,36 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
 		return nil, err
 	}
 
-	renderer := s.engine(req.Chart)
-	files, err := renderer.Render(req.Chart, valuesToRender)
+	hooks, manifestDoc, err := s.renderResources(req.Chart, valuesToRender)
 	if err != nil {
 		return nil, err
 	}
 
+	// Store a release.
+	rel := &release.Release{
+		Name:      name,
+		Namespace: req.Namespace,
+		Chart:     req.Chart,
+		Config:    req.Values,
+		Info: &release.Info{
+			FirstDeployed: ts,
+			LastDeployed:  ts,
+			Status:        &release.Status{Code: release.Status_UNKNOWN},
+		},
+		Manifest: manifestDoc.String(),
+		Hooks:    hooks,
+		Version:  1,
+	}
+	return rel, nil
+}
+
+func (s *releaseServer) renderResources(ch *chart.Chart, values chartutil.Values) ([]*release.Hook, *bytes.Buffer, error) {
+	renderer := s.engine(ch)
+	files, err := renderer.Render(ch, values)
+	if err != nil {
+		return nil, nil, err
+	}
+
 	// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
 	// as partials are not used after renderer.Render. Empty manifests are also
 	// removed here.
@@ -319,7 +386,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
 	if err != nil {
 		// By catching parse errors here, we can prevent bogus releases from going
 		// to Kubernetes.
-		return nil, err
+		return nil, nil, err
 	}
 
 	// Aggregate all valid manifests into one big doc.
@@ -329,22 +396,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
 		b.WriteString(file)
 	}
 
-	// Store a release.
-	rel := &release.Release{
-		Name:      name,
-		Namespace: req.Namespace,
-		Chart:     req.Chart,
-		Config:    req.Values,
-		Info: &release.Info{
-			FirstDeployed: ts,
-			LastDeployed:  ts,
-			Status:        &release.Status{Code: release.Status_UNKNOWN},
-		},
-		Manifest: b.String(),
-		Hooks:    hooks,
-		Version:  1,
-	}
-	return rel, nil
+	return hooks, b, nil
 }
 
 // validateYAML checks to see if YAML is well-formed.
diff --git a/cmd/tiller/release_server_test.go b/cmd/tiller/release_server_test.go
index 37edffac6c6de5b09e729ff28b57b50d091e316e..f2ba5c69aa8f2ce8bf32ebd938cd2661593a3211 100644
--- a/cmd/tiller/release_server_test.go
+++ b/cmd/tiller/release_server_test.go
@@ -45,6 +45,16 @@ data:
   name: value
 `
 
+var manifestWithUpgradeHooks = `apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: test-cm
+  annotations:
+    "helm.sh/hook": post-upgrade,pre-upgrade
+data:
+  name: value
+`
+
 func rsFixture() *releaseServer {
 	return &releaseServer{
 		env: mockEnvironment(),
@@ -80,8 +90,9 @@ func releaseStub() *release.Release {
 			LastDeployed:  &date,
 			Status:        &release.Status{Code: release.Status_DEPLOYED},
 		},
-		Chart:  chartStub(),
-		Config: &chart.Config{Raw: `name = "value"`},
+		Chart:   chartStub(),
+		Config:  &chart.Config{Raw: `name = "value"`},
+		Version: 1,
 		Hooks: []*release.Hook{
 			{
 				Name:     "test-cm",
@@ -290,6 +301,105 @@ func TestInstallReleaseReuseName(t *testing.T) {
 	}
 }
 
+func TestUpdateRelease(t *testing.T) {
+	c := context.Background()
+	rs := rsFixture()
+	rel := releaseStub()
+	rs.env.Releases.Create(rel)
+
+	req := &services.UpdateReleaseRequest{
+		Name: rel.Name,
+		Chart: &chart.Chart{
+			Metadata: &chart.Metadata{Name: "hello"},
+			Templates: []*chart.Template{
+				{Name: "hello", Data: []byte("hello: world")},
+				{Name: "hooks", Data: []byte(manifestWithUpgradeHooks)},
+			},
+		},
+	}
+	res, err := rs.UpdateRelease(c, req)
+	if err != nil {
+		t.Errorf("Failed updated: %s", err)
+	}
+
+	if res.Release.Name == "" {
+		t.Errorf("Expected release name.")
+	}
+
+	if res.Release.Name != rel.Name {
+		t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name)
+	}
+
+	if res.Release.Namespace != rel.Namespace {
+		t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
+	}
+
+	updated, err := rs.env.Releases.Get(res.Release.Name)
+	if err != nil {
+		t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
+	}
+
+	if len(updated.Hooks) != 1 {
+		t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
+	}
+	if updated.Hooks[0].Manifest != manifestWithUpgradeHooks {
+		t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest)
+	}
+
+	if updated.Hooks[0].Events[0] != release.Hook_POST_UPGRADE {
+		t.Errorf("Expected event 0 to be post upgrade")
+	}
+
+	if updated.Hooks[0].Events[1] != release.Hook_PRE_UPGRADE {
+		t.Errorf("Expected event 0 to be pre upgrade")
+	}
+
+	if len(res.Release.Manifest) == 0 {
+		t.Errorf("No manifest returned: %v", res.Release)
+	}
+
+	if len(updated.Manifest) == 0 {
+		t.Errorf("Expected manifest in %v", res)
+	}
+
+	if !strings.Contains(updated.Manifest, "---\n# Source: hello/hello\nhello: world") {
+		t.Errorf("unexpected output: %s", rel.Manifest)
+	}
+
+	if res.Release.Version != 2 {
+		t.Errorf("Expected release version to be %v, got %v", 2, res.Release.Version)
+	}
+}
+
+func TestUpdateReleaseNoHooks(t *testing.T) {
+	c := context.Background()
+	rs := rsFixture()
+	rel := releaseStub()
+	rs.env.Releases.Create(rel)
+
+	req := &services.UpdateReleaseRequest{
+		Name:         rel.Name,
+		DisableHooks: true,
+		Chart: &chart.Chart{
+			Metadata: &chart.Metadata{Name: "hello"},
+			Templates: []*chart.Template{
+				{Name: "hello", Data: []byte("hello: world")},
+				{Name: "hooks", Data: []byte(manifestWithUpgradeHooks)},
+			},
+		},
+	}
+
+	res, err := rs.UpdateRelease(c, req)
+	if err != nil {
+		t.Errorf("Failed updated: %s", err)
+	}
+
+	if hl := res.Release.Hooks[0].LastRun; hl != nil {
+		t.Errorf("Expected that no hooks were run. Got %d", hl)
+	}
+
+}
+
 func TestUninstallRelease(t *testing.T) {
 	c := context.Background()
 	rs := rsFixture()
diff --git a/docs/architecture.md b/docs/architecture.md
index de69b75538c5aee7f61d8823cfcd6214447a7c18..272431eb7d70a4821cd5ce2e4fb3ebde7e9f0dc3 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -75,9 +75,8 @@ The Go files generated from the `proto` definitions are stored in
 Docker images are built by cross-compiling Linux binaries and then
 building a Docker image from the files in `rootfs`.
 
-The `scripts/` directory contains a number of utility scripts, including
-`local-cluster.sh`, which can start a full Kubernetes instance inside of
-a Docker container.
+The `scripts/` directory contains a number of utility scripts. Most of these
+are used by the CI/CD pipeline.
 
 Go dependencies are managed with
 [Glide](https://github.com/Masterminds/glide) and stored in the
diff --git a/docs/charts.md b/docs/charts.md
index 7ac3dd2c661cc628d5ea33df00fac17e015fc2b3..03eecba043c6fc0f398a69da3b748ed4fb159bef 100644
--- a/docs/charts.md
+++ b/docs/charts.md
@@ -202,6 +202,11 @@ sensitive_.
 - `Chart`: The contents of the `Chart.yaml`. Thus, the chart version is
   obtainable as `Chart.Version` and the maintainers are in
   `Chart.Maintainers`.
+- `Files`: A map-like object containing all non-special files in the chart. This
+  will not give you access to templates, but will give you access to additional
+  files that are present. Files can be accessed using `{{index .Files "file.name"}}`
+  or using the `{{.Files.Get name}}` or `{{.Files.GetString name}}` functions. Note that
+  file data is returned as a `[]byte` unless `{{.Files.GetString}}` is used.
 
 **NOTE:** Any unknown Chart.yaml fields will be dropped. They will not
 be accessible inside of the `Chart` object. Thus, Chart.yaml cannot be
diff --git a/docs/developers.md b/docs/developers.md
index 79ece066abc719129b3fe0c496f233ed26d604b4..5ebdc58fe6b962a30245596648c645be6c49b0d0 100644
--- a/docs/developers.md
+++ b/docs/developers.md
@@ -66,11 +66,31 @@ GCR registry.
 
 ## Running a Local Cluster
 
-You can run tests locally using the `scripts/local-cluster.sh` script to
-start Kubernetes inside of a Docker container. For OS X, you will need
-to be running `docker-machine`.
+For development, we highly recommend using the
+[Kubernetes Minikube](https://github.com/kubernetes/minikube)
+developer-oriented distribution. Once this is installed, you can use 
+`helm init` to install into the cluster.
 
-Tiller should run on any >= 1.2 Kubernetes cluster with beta extensions.
+For developing on Tiller, it is sometimes more expedient to run Tiller locally
+instead of packaging it into an image and running it in-cluster. You can do
+this by telling the Helm client to us a local instance.
+
+```console
+$ make build
+$ bin/tiller
+```
+
+And to configure the Helm client, use the `--host` flag or export the `HELM_HOST`
+environment variable:
+
+```console
+$ export HELM_HOST=localhost:44134
+$ helm install foo
+```
+
+(Note that you do not need to use `helm init` when you are running Tiller directly)
+
+Tiller should run on any >= 1.3 Kubernetes cluster.
 
 ## Contribution Guidelines
 
diff --git a/glide.lock b/glide.lock
index 84dbc29a65acfb5d6982e10c85686db5fcc49f69..ba850229855e462640840125e14a9c6ea52aac12 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,10 +1,10 @@
-hash: 141ef5b9c491c91b026ab4007e48502c9a6df9f173c40e1406233dd44f065190
-updated: 2016-07-05T16:51:52.631048739-07:00
+hash: d3f3df18316dca3703f5d073e8f9b1e6bfdb27e8d7fc9c5d742afeddebb022db
+updated: 2016-07-30T23:52:42.581826208-07:00
 imports:
 - name: github.com/aokoli/goutils
   version: 9c37978a95bd5c709a15883b6242714ea6709e64
 - name: github.com/asaskevich/govalidator
-  version: df81827fdd59d8b4fb93d8910b286ab7a3919520
+  version: 7664702784775e51966f0885f5cd27435916517b
 - name: github.com/beorn7/perks
   version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
   subpackages:
@@ -133,7 +133,7 @@ imports:
   - ptypes/any
   - ptypes/timestamp
 - name: github.com/google/cadvisor
-  version: 4dbefc9b671b81257973a33211fb12370c1a526e
+  version: c2ea32971ae033041f0fb0f309b1dee94fd1d55f
   subpackages:
   - api
   - cache/memory
@@ -267,15 +267,15 @@ imports:
 - name: google.golang.org/appengine
   version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
   subpackages:
+  - urlfetch
   - internal
+  - internal/urlfetch
   - internal/app_identity
+  - internal/modules
   - internal/base
   - internal/datastore
   - internal/log
-  - internal/modules
   - internal/remote_api
-  - urlfetch
-  - internal/urlfetch
 - name: google.golang.org/cloud
   version: eb47ba841d53d93506cfbfbc03927daf9cc48f88
   subpackages:
@@ -297,40 +297,67 @@ imports:
 - name: gopkg.in/yaml.v2
   version: a83829b6f1293c91addabc89d0571c246397bbf4
 - name: k8s.io/kubernetes
-  version: 283137936a498aed572ee22af6774b6fb6e9fd94
+  version: e7f022c926583ed8e755a52f23abc4cf8b532d12
   subpackages:
   - pkg/api
   - pkg/api/meta
+  - pkg/api/error
   - pkg/client/restclient
   - pkg/client/unversioned
+  - pkg/apis/batch
   - pkg/client/unversioned/clientcmd
   - pkg/client/unversioned/fake
   - pkg/client/unversioned/portforward
   - pkg/client/unversioned/remotecommand
+  - pkg/kubectl
   - pkg/kubectl/cmd/util
   - pkg/kubectl/resource
   - pkg/labels
+  - pkg/runtime
+  - pkg/watch
   - pkg/api/errors
+  - pkg/client/unversioned/testclient
   - pkg/api/meta/metatypes
   - pkg/api/resource
   - pkg/api/unversioned
   - pkg/auth/user
   - pkg/conversion
   - pkg/fields
-  - pkg/runtime
   - pkg/runtime/serializer
   - pkg/types
   - pkg/util
   - pkg/util/intstr
   - pkg/util/rand
   - pkg/util/sets
+  - pkg/api/install
+  - pkg/apimachinery/registered
+  - pkg/apis/apps
+  - pkg/apis/apps/install
+  - pkg/apis/authentication.k8s.io/install
+  - pkg/apis/authorization/install
+  - pkg/apis/autoscaling
+  - pkg/apis/autoscaling/install
+  - pkg/apis/batch/install
+  - pkg/apis/batch/v2alpha1
+  - pkg/apis/componentconfig/install
+  - pkg/apis/extensions
+  - pkg/apis/extensions/install
+  - pkg/apis/policy
+  - pkg/apis/policy/install
+  - pkg/apis/rbac
+  - pkg/apis/rbac/install
+  - pkg/client/typed/discovery
+  - pkg/util/net
+  - pkg/util/wait
+  - pkg/version
+  - plugin/pkg/client/auth
+  - pkg/util/validation
+  - pkg/util/validation/field
   - pkg/client/unversioned/auth
   - pkg/client/unversioned/clientcmd/api
   - pkg/client/unversioned/clientcmd/api/latest
   - pkg/util/errors
   - pkg/util/homedir
-  - pkg/util/validation
-  - pkg/util/validation/field
   - pkg/kubelet/server/portforward
   - pkg/util/httpstream
   - pkg/util/runtime
@@ -339,42 +366,53 @@ imports:
   - pkg/util/httpstream/spdy
   - federation/apis/federation
   - federation/client/clientset_generated/federation_internalclientset
-  - pkg/api/service
+  - pkg/api/annotations
+  - pkg/api/util
+  - pkg/api/v1
   - pkg/api/validation
-  - pkg/apimachinery
-  - pkg/apimachinery/registered
-  - pkg/apis/apps
-  - pkg/apis/autoscaling
-  - pkg/apis/batch
-  - pkg/apis/extensions
-  - pkg/apis/policy
-  - pkg/apis/rbac
-  - pkg/client/typed/discovery
+  - pkg/apis/batch/v1
+  - pkg/client/clientset_generated/internalclientset
   - pkg/client/unversioned/adapters/internalclientset
+  - pkg/credentialprovider
+  - pkg/fieldpath
+  - pkg/kubelet/qos/util
+  - pkg/util/deployment
+  - pkg/util/integer
+  - pkg/util/jsonpath
+  - pkg/util/slice
+  - pkg/api/service
+  - pkg/apimachinery
   - pkg/controller
-  - pkg/kubectl
   - pkg/registry/thirdpartyresourcedata
   - pkg/runtime/serializer/json
   - pkg/util/flag
   - pkg/util/strategicpatch
-  - pkg/watch
   - pkg/util/yaml
-  - pkg/api/testapi
-  - third_party/forked/reflect
   - pkg/conversion/queryparams
   - pkg/util/json
+  - pkg/api/testapi
+  - third_party/forked/reflect
   - pkg/runtime/serializer/protobuf
   - pkg/runtime/serializer/recognizer
   - pkg/runtime/serializer/versioning
-  - pkg/util/wait
-  - pkg/api/v1
+  - pkg/watch/versioned
+  - pkg/apis/apps/v1alpha1
+  - pkg/apis/authentication.k8s.io
+  - pkg/apis/authentication.k8s.io/v1beta1
+  - pkg/apis/authorization
+  - pkg/apis/authorization/v1beta1
+  - pkg/apis/autoscaling/v1
+  - pkg/apis/componentconfig
+  - pkg/apis/componentconfig/v1alpha1
+  - pkg/apis/extensions/v1beta1
+  - pkg/apis/policy/v1alpha1
+  - pkg/apis/rbac/v1alpha1
   - pkg/client/metrics
   - pkg/runtime/serializer/streaming
   - pkg/util/crypto
   - pkg/util/flowcontrol
-  - pkg/util/net
-  - pkg/version
-  - pkg/watch/versioned
+  - plugin/pkg/client/auth/gcp
+  - plugin/pkg/client/auth/oidc
   - pkg/client/unversioned/clientcmd/api/v1
   - pkg/httplog
   - pkg/util/wsstream
@@ -382,71 +420,35 @@ imports:
   - federation/apis/federation/install
   - federation/client/clientset_generated/federation_internalclientset/typed/core/unversioned
   - federation/client/clientset_generated/federation_internalclientset/typed/federation/unversioned
-  - pkg/util/net/sets
+  - pkg/util/parsers
   - pkg/api/endpoints
   - pkg/api/pod
   - pkg/api/unversioned/validation
-  - pkg/api/util
   - pkg/capabilities
-  - pkg/api/install
-  - pkg/apis/apps/install
-  - pkg/apis/authentication.k8s.io/install
-  - pkg/apis/authorization/install
-  - pkg/apis/autoscaling/install
-  - pkg/apis/batch/install
-  - pkg/apis/batch/v2alpha1
-  - pkg/apis/componentconfig/install
-  - pkg/apis/extensions/install
-  - pkg/apis/policy/install
-  - pkg/apis/rbac/install
-  - plugin/pkg/client/auth
-  - pkg/client/clientset_generated/internalclientset
+  - pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned
   - pkg/client/clientset_generated/internalclientset/typed/batch/unversioned
   - pkg/client/clientset_generated/internalclientset/typed/core/unversioned
   - pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned
+  - pkg/client/clientset_generated/internalclientset/typed/rbac/unversioned
+  - pkg/util/labels
+  - pkg/util/pod
+  - pkg/util/replicaset
+  - third_party/golang/template
+  - pkg/util/net/sets
   - pkg/client/cache
   - pkg/client/record
   - pkg/controller/framework
   - pkg/util/hash
-  - pkg/util/integer
-  - pkg/api/annotations
-  - pkg/apis/batch/v1
-  - pkg/credentialprovider
-  - pkg/fieldpath
-  - pkg/kubelet/qos/util
-  - pkg/util/deployment
-  - pkg/util/jsonpath
-  - pkg/util/slice
   - pkg/api/rest
-  - pkg/apis/extensions/v1beta1
   - pkg/apis/extensions/validation
   - pkg/registry/generic
   - pkg/util/framer
   - third_party/forked/json
-  - pkg/util/parsers
+  - pkg/kubelet/qos
+  - pkg/master/ports
   - federation/apis/federation/v1beta1
-  - pkg/apis/apps/v1alpha1
-  - pkg/apis/authentication.k8s.io
-  - pkg/apis/authentication.k8s.io/v1beta1
-  - pkg/apis/authorization
-  - pkg/apis/authorization/v1beta1
-  - pkg/apis/autoscaling/v1
-  - pkg/apis/componentconfig
-  - pkg/apis/componentconfig/v1alpha1
-  - pkg/apis/policy/v1alpha1
-  - pkg/apis/rbac/v1alpha1
-  - plugin/pkg/client/auth/gcp
-  - plugin/pkg/client/auth/oidc
-  - pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned
-  - pkg/client/clientset_generated/internalclientset/typed/rbac/unversioned
-  - pkg/util/labels
-  - pkg/util/pod
-  - pkg/util/replicaset
-  - third_party/golang/template
   - pkg/security/podsecuritypolicy/util
   - pkg/storage
-  - pkg/kubelet/qos
-  - pkg/master/ports
 - name: speter.net/go/exp/math/dec/inf
   version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
   repo: https://github.com/go-inf/inf.git
diff --git a/glide.yaml b/glide.yaml
index aa7271cdec836b3a36f289b5936c94010f8c76eb..03917acf4c3a5c9390a03233b3d7be41a6db7bbe 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -22,22 +22,32 @@ import:
 - package: google.golang.org/grpc
   version: dec33edc378cf4971a2741cfd86ed70a644d6ba3
 - package: k8s.io/kubernetes
-  version: v1.3.0
+  version: ~1.3
   subpackages:
   - pkg/api
   - pkg/api/meta
+  - pkg/api/error
+  - pkg/api/unversioned
+  - pkg/apimachinery/registered
   - pkg/client/restclient
   - pkg/client/unversioned
+  - pkg/apis/batch
   - pkg/client/unversioned/clientcmd
   - pkg/client/unversioned/fake
   - pkg/client/unversioned/portforward
   - pkg/client/unversioned/remotecommand
+  - pkg/kubectl
   - pkg/kubectl/cmd/util
   - pkg/kubectl/resource
   - pkg/labels
+  - pkg/runtime
+  - pkg/watch
+  - pkg/util/strategicpatch
+  - pkg/util/yaml
 - package: github.com/gosuri/uitable
 - package: speter.net/go/exp/math/dec/inf
+  version: ^0.9.0
   repo: https://github.com/go-inf/inf.git
   vcs: git
 - package: github.com/asaskevich/govalidator
-- package: github.com/satori/go.uuid
+  version: ^4.0.0
diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go
index f2b4c300e45211c84e97cc98e4a6eacfccefe171..8d0990e0682e8cb4a33a0300d1865592ccf34757 100644
--- a/pkg/chartutil/create.go
+++ b/pkg/chartutil/create.go
@@ -48,7 +48,23 @@ const defaultIgnore = `# Patterns to ignore when building packages.
 # This supports shell glob matching, relative path matching, and
 # negation (prefixed with !). Only one pattern per line.
 .DS_Store
-.git
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
 `
 
 // Create creates a new chart in a directory.
diff --git a/pkg/chartutil/files.go b/pkg/chartutil/files.go
index 45598de3a1cec84fa447b00a8e2649bbde736ee1..89120a42fbf248bdad060cd8a25c8b410fb0ce18 100644
--- a/pkg/chartutil/files.go
+++ b/pkg/chartutil/files.go
@@ -32,11 +32,14 @@ func NewFiles(from []*any.Any) Files {
 	return files
 }
 
-// Get a file by path.
+// GetBytes gets a file by path.
+//
+// The returned data is raw. In a template context, this is identical to calling
+// {{index .Files $path}}.
 //
 // This is intended to be accessed from within a template, so a missed key returns
 // an empty []byte.
-func (f Files) Get(name string) []byte {
+func (f Files) GetBytes(name string) []byte {
 	v, ok := f[name]
 	if !ok {
 		return []byte{}
@@ -44,10 +47,12 @@ func (f Files) Get(name string) []byte {
 	return v
 }
 
-// GetString returns a string representation of the given file.
+// Get returns a string representation of the given file.
+//
+// Fetch the contents of a file as a string. It is designed to be called in a
+// template.
 //
-// This is a convenience for the otherwise cumbersome template logic
-// for '{{.Files.Get "foo" | printf "%s"}}'.
-func (f Files) GetString(name string) string {
-	return string(f.Get(name))
+//	{{.Files.Get "foo"}}
+func (f Files) Get(name string) string {
+	return string(f.GetBytes(name))
 }
diff --git a/pkg/chartutil/files_test.go b/pkg/chartutil/files_test.go
index 97eb4ee0529f8866399e6e1e0011c17f0cb30216..5e162f19d820047a486ba2d295beb2c5bf50ba3b 100644
--- a/pkg/chartutil/files_test.go
+++ b/pkg/chartutil/files_test.go
@@ -43,10 +43,10 @@ func TestNewFiles(t *testing.T) {
 	}
 
 	for i, f := range cases {
-		if got := string(files.Get(f.path)); got != f.data {
+		if got := string(files.GetBytes(f.path)); got != f.data {
 			t.Errorf("%d: expected %q, got %q", i, f.data, got)
 		}
-		if got := files.GetString(f.path); got != f.data {
+		if got := files.Get(f.path); got != f.data {
 			t.Errorf("%d: expected %q, got %q", i, f.data, got)
 		}
 	}
diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go
index 296b11231c2cfcecc423e89f31534a078e0220be..911d883d2cf715796ebfa530a57d9eb96a3646fb 100644
--- a/pkg/chartutil/load.go
+++ b/pkg/chartutil/load.go
@@ -218,6 +218,11 @@ func LoadDir(dir string) (*chart.Chart, error) {
 			return err
 		}
 		if fi.IsDir() {
+			// Directory-based ignore rules should involve skipping the entire
+			// contents of that directory.
+			if rules.Ignore(n, fi) {
+				return filepath.SkipDir
+			}
 			return nil
 		}
 
diff --git a/pkg/chartutil/load_test.go b/pkg/chartutil/load_test.go
index fa94acbc339c0ebc9756ed91a5e4055332a719f5..822e8d0783db554301d39f81e9ced6315c5c8252 100644
--- a/pkg/chartutil/load_test.go
+++ b/pkg/chartutil/load_test.go
@@ -49,8 +49,9 @@ func verifyChart(t *testing.T, c *chart.Chart) {
 		t.Errorf("Expected 1 template, got %d", len(c.Templates))
 	}
 
-	if len(c.Files) != 5 {
-		t.Errorf("Expected 5 extra files, got %d", len(c.Files))
+	numfiles := 6
+	if len(c.Files) != numfiles {
+		t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files))
 		for _, n := range c.Files {
 			t.Logf("\t%s", n.TypeUrl)
 		}
diff --git a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz
index 31c855223046ed3bba9abb2a7ca707195ad6daa4..50d1ef01484094a445c867e612e363f4f527d604 100644
Binary files a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz and b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz differ
diff --git a/pkg/chartutil/testdata/frobnitz/.helmignore b/pkg/chartutil/testdata/frobnitz/.helmignore
new file mode 100644
index 0000000000000000000000000000000000000000..9973a57b8035d98658162558e488aa24f7d8fa15
--- /dev/null
+++ b/pkg/chartutil/testdata/frobnitz/.helmignore
@@ -0,0 +1 @@
+ignore/
diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz
index 90c7979afe88fb36ef00f6fe09041217b874323f..27bd51f654f64fa50e431c35bd69c9e7d509a5c1 100644
Binary files a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz and b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz differ
diff --git a/pkg/chartutil/testdata/frobnitz/ignore/me.txt b/pkg/chartutil/testdata/frobnitz/ignore/me.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pkg/chartutil/testdata/genfrob.sh b/pkg/chartutil/testdata/genfrob.sh
index 38fc1b22c959826615ed5f6e244465a540d7b6d5..8f2cddec1a4da9ed6610f5d033d1835d5aaf9e13 100755
--- a/pkg/chartutil/testdata/genfrob.sh
+++ b/pkg/chartutil/testdata/genfrob.sh
@@ -9,4 +9,4 @@ tar -zcvf frobnitz/charts/mariner-4.3.2.tgz mariner
 
 # Pack the frobnitz chart.
 echo "Packing frobnitz"
-tar -zcvf frobnitz-1.2.3.tgz frobnitz
+tar --exclude=ignore/* -zcvf frobnitz-1.2.3.tgz frobnitz
diff --git a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz
index 3d5b6a2420ffcdf46d8f9de74f056c4d7e47bb9e..c35e1b9701734924198f1739129a9563f75ba7cd 100644
Binary files a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz and b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz differ
diff --git a/pkg/client/install.go b/pkg/client/install.go
index 1ffbb5b775be5dfcbca663408c5dac612d2a3282..0b7a3b1fc4102e45954cc35c30c92b4e218e95d2 100644
--- a/pkg/client/install.go
+++ b/pkg/client/install.go
@@ -66,19 +66,13 @@ func Install(namespace, image string, verbose bool) error {
 // InstallYAML is the installation YAML for DM.
 const InstallYAML = `
 ---
-apiVersion: v1
-kind: ReplicationController
+apiVersion: extensions/v1beta1
+kind: Deployment
 metadata:
-  labels:
-    app: helm
-    name: tiller
-  name: tiller-rc
+  name: tiller-deploy
   namespace: {{ .Namespace }}
 spec:
   replicas: 1
-  selector:
-    app: helm
-    name: tiller
   template:
     metadata:
       labels:
diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go
index cb88088e6e448aeb6499fd210735ac2f2f3a1db4..73b8dabad0b68bc3d35ccff6297e8fb1ff2165d9 100644
--- a/pkg/engine/engine.go
+++ b/pkg/engine/engine.go
@@ -88,6 +88,28 @@ type renderable struct {
 	vals chartutil.Values
 }
 
+// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
+//
+// The resulting FuncMap is only valid for the passed-in template.
+func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
+	// Clone the func map because we are adding context-specific functions.
+	var funcMap template.FuncMap = map[string]interface{}{}
+	for k, v := range e.FuncMap {
+		funcMap[k] = v
+	}
+
+	// Add the 'include' function here so we can close over t.
+	funcMap["include"] = func(name string, data interface{}) string {
+		buf := bytes.NewBuffer(nil)
+		if err := t.ExecuteTemplate(buf, name, data); err != nil {
+			buf.WriteString(err.Error())
+		}
+		return buf.String()
+	}
+
+	return funcMap
+}
+
 // render takes a map of templates/values and renders them.
 func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
 	// Basically, what we do here is start with an empty parent template and then
@@ -105,10 +127,13 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
 		// but will still emit <no value> for others. We mitigate that later.
 		t.Option("missingkey=zero")
 	}
+
+	funcMap := e.alterFuncMap(t)
+
 	files := []string{}
 	for fname, r := range tpls {
 		log.Printf("Preparing template %s", fname)
-		t = t.New(fname).Funcs(e.FuncMap)
+		t = t.New(fname).Funcs(funcMap)
 		if _, err := t.Parse(r.tpl); err != nil {
 			return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
 		}
diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go
index 03ee083dc1ff5f13e74d16a9565e51e9d0d9b2d6..ec19f8ded62cd8601b4d68171d15e581d1f72b36 100644
--- a/pkg/engine/engine_test.go
+++ b/pkg/engine/engine_test.go
@@ -312,7 +312,7 @@ func TestRenderBuiltinValues(t *testing.T) {
 		Metadata: &chart.Metadata{Name: "Latium"},
 		Templates: []*chart.Template{
 			{Name: "Lavinia", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
-			{Name: "From", Data: []byte(`{{.Files.author | printf "%s"}} {{.Files.GetString "book/title.txt"}}`)},
+			{Name: "From", Data: []byte(`{{.Files.author | printf "%s"}} {{.Files.Get "book/title.txt"}}`)},
 		},
 		Values:       &chart.Config{Raw: ``},
 		Dependencies: []*chart.Chart{},
@@ -358,3 +358,33 @@ func TestRenderBuiltinValues(t *testing.T) {
 	}
 
 }
+
+func TestAlterFuncMap(t *testing.T) {
+	c := &chart.Chart{
+		Metadata: &chart.Metadata{Name: "conrad"},
+		Templates: []*chart.Template{
+			{Name: "quote", Data: []byte(`{{include "conrad/_partial" . | indent 2}} dead.`)},
+			{Name: "_partial", Data: []byte(`{{.Release.Name}} - he`)},
+		},
+		Values:       &chart.Config{Raw: ``},
+		Dependencies: []*chart.Chart{},
+	}
+
+	v := chartutil.Values{
+		"Values": &chart.Config{Raw: ""},
+		"Chart":  c.Metadata,
+		"Release": chartutil.Values{
+			"Name": "Mistah Kurtz",
+		},
+	}
+
+	out, err := New().Render(c, v)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expect := "  Mistah Kurtz - he dead."
+	if got := out["conrad/quote"]; got != expect {
+		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
+	}
+}
diff --git a/pkg/helm/option.go b/pkg/helm/option.go
index 98a6efc19fe2515fe57e5825673977560b8387e4..2af4742da22cf84bb25eab46024de9637461b612 100644
--- a/pkg/helm/option.go
+++ b/pkg/helm/option.go
@@ -143,6 +143,13 @@ func DeleteDryRun(dry bool) DeleteOption {
 	}
 }
 
+// UpgradeDisableHooks will disable hooks for an upgrade operation.
+func UpgradeDisableHooks(disable bool) UpdateOption {
+	return func(opts *options) {
+		opts.disableHooks = disable
+	}
+}
+
 // UpgradeDryRun will (if true) execute an upgrade as a dry run.
 func UpgradeDryRun(dry bool) UpdateOption {
 	return func(opts *options) {
@@ -237,9 +244,15 @@ func (o *options) rpcDeleteRelease(rlsName string, rlc rls.ReleaseServiceClient,
 
 // Executes tiller.UpdateRelease RPC.
 func (o *options) rpcUpdateRelease(rlsName string, chr *cpb.Chart, rlc rls.ReleaseServiceClient, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
-	//TODO: handle dryRun
+	for _, opt := range opts {
+		opt(o)
+	}
+
+	o.updateReq.Chart = chr
+	o.updateReq.DryRun = o.dryRun
+	o.updateReq.Name = rlsName
 
-	return rlc.UpdateRelease(context.TODO(), &rls.UpdateReleaseRequest{Name: rlsName, Chart: chr})
+	return rlc.UpdateRelease(context.TODO(), &o.updateReq)
 }
 
 // Executes tiller.GetReleaseStatus RPC.
diff --git a/pkg/ignore/rules.go b/pkg/ignore/rules.go
index 0251268baf899ad974821c409590e4d3385b80aa..f5b08a4eebeff7d4fd7c494175c44de06bcfa831 100644
--- a/pkg/ignore/rules.go
+++ b/pkg/ignore/rules.go
@@ -65,7 +65,6 @@ func Parse(file io.Reader) (*Rules, error) {
 	if err := s.Err(); err != nil {
 		return r, err
 	}
-
 	return r, nil
 }
 
@@ -97,8 +96,10 @@ func (r *Rules) Ignore(path string, fi os.FileInfo) bool {
 			continue
 		}
 
+		// If the rule is looking for directories, and this is not a directory,
+		// skip it.
 		if p.mustDir && !fi.IsDir() {
-			return false
+			continue
 		}
 		if p.match(path, fi) {
 			return true
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index 4e0c519086f67ab542865a7db8700e638111d928..da073d173f169d848c789e6e5f3a6a4f0925f6af 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -20,15 +20,21 @@ import (
 	"fmt"
 	"io"
 	"log"
+	"reflect"
 	"time"
 
 	"k8s.io/kubernetes/pkg/api"
 	"k8s.io/kubernetes/pkg/api/errors"
+	"k8s.io/kubernetes/pkg/api/unversioned"
+	"k8s.io/kubernetes/pkg/apimachinery/registered"
 	"k8s.io/kubernetes/pkg/apis/batch"
 	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
 	"k8s.io/kubernetes/pkg/kubectl"
 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 	"k8s.io/kubernetes/pkg/kubectl/resource"
+	"k8s.io/kubernetes/pkg/runtime"
+	"k8s.io/kubernetes/pkg/util/strategicpatch"
+	"k8s.io/kubernetes/pkg/util/yaml"
 	"k8s.io/kubernetes/pkg/watch"
 )
 
@@ -57,6 +63,77 @@ func (c *Client) Create(namespace string, reader io.Reader) error {
 	return perform(c, namespace, reader, createResource)
 }
 
+// Update reads in the current configuration and a modified configuration from io.reader
+//  and creates resources that don't already exists, updates resources that have been modified
+//  and deletes resources from the current configuration that are not present in the
+//  modified configuration
+//
+// Namespace will set the namespaces
+func (c *Client) Update(namespace string, currentReader, modifiedReader io.Reader) error {
+	current := c.NewBuilder(includeThirdPartyAPIs).
+		ContinueOnError().
+		NamespaceParam(namespace).
+		DefaultNamespace().
+		Stream(currentReader, "").
+		Flatten().
+		Do()
+
+	modified := c.NewBuilder(includeThirdPartyAPIs).
+		ContinueOnError().
+		NamespaceParam(namespace).
+		DefaultNamespace().
+		Stream(modifiedReader, "").
+		Flatten().
+		Do()
+
+	currentInfos, err := current.Infos()
+	if err != nil {
+		return err
+	}
+
+	modifiedInfos := []*resource.Info{}
+
+	modified.Visit(func(info *resource.Info, err error) error {
+		modifiedInfos = append(modifiedInfos, info)
+		if err != nil {
+			return err
+		}
+		resourceName := info.Name
+
+		helper := resource.NewHelper(info.Client, info.Mapping)
+		if _, err := helper.Get(info.Namespace, resourceName, info.Export); err != nil {
+			if !errors.IsNotFound(err) {
+				return fmt.Errorf("Could not get information about the resource: err: %s", err)
+			}
+
+			// Since the resource does not exist, create it.
+			if err := createResource(info); err != nil {
+				return err
+			}
+
+			kind := info.Mapping.GroupVersionKind.Kind
+			log.Printf("Created a new %s called %s\n", kind, resourceName)
+			return nil
+		}
+
+		currentObj, err := getCurrentObject(resourceName, currentInfos)
+		if err != nil {
+			return err
+		}
+
+		if err := updateResource(info, currentObj); err != nil {
+			log.Printf("error updating the resource %s:\n\t %v", resourceName, err)
+			return err
+		}
+
+		return err
+	})
+
+	deleteUnwantedResources(currentInfos, modifiedInfos)
+
+	return nil
+}
+
 // Delete deletes kubernetes resources from an io.reader
 //
 // Namespace will set the namespace
@@ -136,6 +213,51 @@ func createResource(info *resource.Info) error {
 	return err
 }
 
+func deleteResource(info *resource.Info) error {
+	return resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name)
+}
+
+func updateResource(modified *resource.Info, currentObj runtime.Object) error {
+
+	encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...)
+	originalSerialization, err := runtime.Encode(encoder, currentObj)
+	if err != nil {
+		return err
+	}
+
+	editedSerialization, err := runtime.Encode(encoder, modified.Object)
+	if err != nil {
+		return err
+	}
+
+	originalJS, err := yaml.ToJSON(originalSerialization)
+	if err != nil {
+		return err
+	}
+
+	editedJS, err := yaml.ToJSON(editedSerialization)
+	if err != nil {
+		return err
+	}
+
+	if reflect.DeepEqual(originalJS, editedJS) {
+		return fmt.Errorf("Looks like there are no changes for %s", modified.Name)
+	}
+
+	patch, err := strategicpatch.CreateStrategicMergePatch(originalJS, editedJS, currentObj)
+	if err != nil {
+		return err
+	}
+
+	// send patch to server
+	helper := resource.NewHelper(modified.Client, modified.Mapping)
+	if _, err = helper.Patch(modified.Namespace, modified.Name, api.StrategicMergePatchType, patch); err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func watchUntilReady(info *resource.Info) error {
 	w, err := resource.NewHelper(info.Client, info.Mapping).WatchSingle(info.Namespace, info.Name, info.ResourceVersion)
 	if err != nil {
@@ -213,3 +335,37 @@ func (c *Client) ensureNamespace(namespace string) error {
 	}
 	return nil
 }
+
+func deleteUnwantedResources(currentInfos, modifiedInfos []*resource.Info) {
+	for _, cInfo := range currentInfos {
+		found := false
+		for _, m := range modifiedInfos {
+			if m.Name == cInfo.Name {
+				found = true
+			}
+		}
+		if !found {
+			log.Printf("Deleting %s...", cInfo.Name)
+			if err := deleteResource(cInfo); err != nil {
+				log.Printf("Failed to delete %s, err: %s", cInfo.Name, err)
+			}
+		}
+	}
+}
+
+func getCurrentObject(targetName string, infos []*resource.Info) (runtime.Object, error) {
+	var curr *resource.Info
+	for _, currInfo := range infos {
+		if currInfo.Name == targetName {
+			curr = currInfo
+		}
+	}
+
+	if curr == nil {
+		return nil, fmt.Errorf("No resource with the name %s found.", targetName)
+	}
+
+	encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...)
+	defaultVersion := unversioned.GroupVersion{}
+	return resource.AsVersionedObject([]*resource.Info{curr}, false, defaultVersion, encoder)
+}
diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go
index 5ef8b913eea738844ddd5ca2bf115a94ae4caad7..c59cc37b0acd0dbbc2e9dc7bdbca35d9f3cee5d3 100644
--- a/pkg/kube/client_test.go
+++ b/pkg/kube/client_test.go
@@ -17,15 +17,55 @@ limitations under the License.
 package kube
 
 import (
+	"bytes"
+	"encoding/json"
 	"io"
+	"io/ioutil"
+	"net/http"
 	"strings"
 	"testing"
 
 	"k8s.io/kubernetes/pkg/api/meta"
+	"k8s.io/kubernetes/pkg/api/testapi"
+	"k8s.io/kubernetes/pkg/api/unversioned"
+	api "k8s.io/kubernetes/pkg/api/v1"
 	"k8s.io/kubernetes/pkg/client/unversioned/fake"
 	"k8s.io/kubernetes/pkg/kubectl/resource"
+	"k8s.io/kubernetes/pkg/runtime"
 )
 
+func TestUpdateResource(t *testing.T) {
+
+	tests := []struct {
+		name       string
+		namespace  string
+		modified   *resource.Info
+		currentObj runtime.Object
+		err        bool
+		errMessage string
+	}{
+		{
+			name:       "no changes when updating resources",
+			modified:   createFakeInfo("nginx", nil),
+			currentObj: createFakePod("nginx", nil),
+			err:        true,
+			errMessage: "Looks like there are no changes for nginx",
+		},
+		//{
+		//name:       "valid update input",
+		//modified:   createFakeInfo("nginx", map[string]string{"app": "nginx"}),
+		//currentObj: createFakePod("nginx", nil),
+		//},
+	}
+
+	for _, tt := range tests {
+		err := updateResource(tt.modified, tt.currentObj)
+		if err != nil && err.Error() != tt.errMessage {
+			t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err)
+		}
+	}
+}
+
 func TestPerform(t *testing.T) {
 	tests := []struct {
 		name       string
@@ -214,3 +254,53 @@ spec:
         ports:
         - containerPort: 80
 `
+
+func createFakePod(name string, labels map[string]string) runtime.Object {
+	objectMeta := createObjectMeta(name, labels)
+
+	object := &api.Pod{
+		ObjectMeta: objectMeta,
+	}
+
+	return object
+}
+
+func createFakeInfo(name string, labels map[string]string) *resource.Info {
+	pod := createFakePod(name, labels)
+	marshaledObj, _ := json.Marshal(pod)
+
+	mapping := &meta.RESTMapping{
+		Resource: name,
+		Scope:    meta.RESTScopeNamespace,
+		GroupVersionKind: unversioned.GroupVersionKind{
+			Kind:    "Pod",
+			Version: "v1",
+		}}
+
+	client := &fake.RESTClient{
+		Codec: testapi.Default.Codec(),
+		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
+			header := http.Header{}
+			header.Set("Content-Type", runtime.ContentTypeJSON)
+			return &http.Response{
+				StatusCode: 200,
+				Header:     header,
+				Body:       ioutil.NopCloser(bytes.NewReader(marshaledObj)),
+			}, nil
+		})}
+	info := resource.NewInfo(client, mapping, "default", "nginx", false)
+
+	info.Object = pod
+
+	return info
+}
+
+func createObjectMeta(name string, labels map[string]string) api.ObjectMeta {
+	objectMeta := api.ObjectMeta{Name: name, Namespace: "default"}
+
+	if labels != nil {
+		objectMeta.Labels = labels
+	}
+
+	return objectMeta
+}
diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go
index ff3b76b4202893789c0828d7a15df8f490e8e582..66406d512e27d570c97eec3e65a633c300d08753 100644
--- a/pkg/kube/tunnel.go
+++ b/pkg/kube/tunnel.go
@@ -51,7 +51,7 @@ func (c *Client) ForwardPort(namespace, podName string, remote int) (*Tunnel, er
 	}
 
 	// Build a url to the portforward endpoing
-	// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-rc-9itlq/portforward
+	// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-deploy-9itlq/portforward
 	u := client.RESTClient.Post().
 		Resource("pods").
 		Namespace(namespace).
diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go
index d1cc19ae4f50f95ad2d3ae070351f06ca63a55c7..838e83647e6919a02c24504eba4062bd6f4960ce 100644
--- a/pkg/proto/hapi/services/tiller.pb.go
+++ b/pkg/proto/hapi/services/tiller.pb.go
@@ -226,6 +226,8 @@ type UpdateReleaseRequest struct {
 	Values *hapi_chart.Config `protobuf:"bytes,3,opt,name=values" json:"values,omitempty"`
 	// dry_run, if true, will run through the release logic, but neither create
 	DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"`
+	// DisableHooks causes the server to skip running any hooks for the upgrade.
+	DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
 }
 
 func (m *UpdateReleaseRequest) Reset()                    { *m = UpdateReleaseRequest{} }
@@ -624,54 +626,54 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
 }
 
 var fileDescriptor0 = []byte{
-	// 769 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdb, 0x6e, 0xd3, 0x4a,
-	0x14, 0xad, 0x93, 0xd4, 0x49, 0x76, 0x2f, 0x4a, 0xe7, 0xb4, 0x8d, 0x8f, 0x75, 0x0e, 0x42, 0x46,
-	0x40, 0x29, 0xd4, 0x81, 0xf0, 0x8e, 0x94, 0xb6, 0x51, 0x5b, 0x35, 0xa4, 0xd2, 0x84, 0x82, 0xc4,
-	0x03, 0x91, 0x9b, 0x4c, 0xa8, 0xc1, 0xb5, 0x83, 0x67, 0x52, 0xd1, 0x4f, 0xe0, 0x0f, 0xf8, 0x14,
-	0x3e, 0x88, 0xbf, 0xe0, 0x85, 0xb9, 0xd8, 0x26, 0x17, 0x1b, 0x4c, 0x5f, 0x9c, 0x99, 0xd9, 0x6b,
-	0xaf, 0x7d, 0xdf, 0x0a, 0x98, 0x97, 0xce, 0xd8, 0x6d, 0x50, 0x12, 0x5e, 0xbb, 0x03, 0x42, 0x1b,
-	0xcc, 0xf5, 0x3c, 0x12, 0xda, 0xe3, 0x30, 0x60, 0x01, 0xda, 0x14, 0x32, 0x3b, 0x96, 0xd9, 0x4a,
-	0x66, 0x6e, 0x4b, 0x8d, 0xc1, 0xa5, 0x13, 0x32, 0xf5, 0x55, 0x68, 0xb3, 0x3e, 0xfd, 0x1e, 0xf8,
-	0x23, 0xf7, 0x7d, 0x24, 0x50, 0x26, 0x42, 0xe2, 0x11, 0x87, 0x92, 0xf8, 0x77, 0x46, 0x29, 0x96,
-	0xb9, 0xfe, 0x28, 0x50, 0x02, 0xeb, 0xbb, 0x06, 0xff, 0x74, 0x5c, 0xca, 0xb0, 0x12, 0x51, 0x4c,
-	0x3e, 0x4d, 0x08, 0x65, 0x68, 0x13, 0x96, 0x3d, 0xf7, 0xca, 0x65, 0x86, 0x76, 0x57, 0xdb, 0x29,
-	0x62, 0x75, 0x41, 0xdb, 0xa0, 0x07, 0xa3, 0x11, 0x25, 0xcc, 0x28, 0xf0, 0xe7, 0x2a, 0x8e, 0x6e,
-	0xe8, 0x05, 0x94, 0x69, 0x10, 0xb2, 0xfe, 0xc5, 0x8d, 0x51, 0xe4, 0x82, 0xf5, 0xe6, 0x7d, 0x3b,
-	0x2d, 0x26, 0x5b, 0x58, 0xea, 0x71, 0xa0, 0x2d, 0x3e, 0xfb, 0x37, 0x58, 0xa7, 0xf2, 0x57, 0xf0,
-	0x8e, 0x5c, 0x8f, 0x91, 0xd0, 0x28, 0x29, 0x5e, 0x75, 0x43, 0x47, 0x00, 0x92, 0x37, 0x08, 0x87,
-	0x5c, 0xb6, 0x2c, 0xa9, 0x77, 0x72, 0x50, 0x9f, 0x09, 0x3c, 0xae, 0xd2, 0xf8, 0x68, 0xbd, 0x83,
-	0x4a, 0x0c, 0xb0, 0x9a, 0xa0, 0x2b, 0xf3, 0x68, 0x05, 0xca, 0xe7, 0xdd, 0xd3, 0xee, 0xd9, 0x9b,
-	0x6e, 0x6d, 0x09, 0x55, 0xa0, 0xd4, 0x6d, 0xbd, 0x6c, 0xd7, 0x34, 0xb4, 0x01, 0x6b, 0x9d, 0x56,
-	0xef, 0x55, 0x1f, 0xb7, 0x3b, 0xed, 0x56, 0xaf, 0x7d, 0x58, 0x2b, 0x58, 0x77, 0xa0, 0x9a, 0xf0,
-	0xa2, 0x32, 0x14, 0x5b, 0xbd, 0x03, 0xa5, 0x72, 0xd8, 0xe6, 0x27, 0xcd, 0xfa, 0xa2, 0xc1, 0xe6,
-	0x6c, 0x1a, 0xe9, 0x38, 0xf0, 0x29, 0x11, 0x79, 0x1c, 0x04, 0x13, 0x3f, 0xc9, 0xa3, 0xbc, 0x20,
-	0x04, 0x25, 0x9f, 0x7c, 0x8e, 0xb3, 0x28, 0xcf, 0x02, 0xc9, 0x02, 0xe6, 0x78, 0x32, 0x83, 0x1c,
-	0x29, 0x2f, 0xe8, 0x19, 0x54, 0xa2, 0xaa, 0x51, 0x9e, 0x9b, 0xe2, 0xce, 0x4a, 0x73, 0x4b, 0xc5,
-	0x1f, 0xd7, 0x37, 0xb2, 0x88, 0x13, 0x98, 0xb5, 0x07, 0xf5, 0x23, 0x12, 0x7b, 0xd2, 0x63, 0x0e,
-	0x9b, 0x24, 0x55, 0x15, 0x76, 0x9d, 0x2b, 0x22, 0x9d, 0x11, 0x76, 0xf9, 0xd9, 0x7a, 0x0d, 0xc6,
-	0x22, 0x3c, 0xf2, 0x3e, 0x05, 0x8f, 0x1e, 0x40, 0x49, 0xf4, 0x8f, 0xf4, 0x7d, 0xa5, 0x89, 0x66,
-	0xbd, 0x39, 0xe1, 0x12, 0x2c, 0xe5, 0x96, 0x3d, 0xcd, 0x7b, 0x10, 0xf8, 0x8c, 0xf8, 0xec, 0x77,
-	0x7e, 0x74, 0xe0, 0xdf, 0x14, 0x7c, 0xe4, 0x48, 0x03, 0xca, 0x91, 0x09, 0xa9, 0x93, 0x99, 0x85,
-	0x18, 0x65, 0x7d, 0xe5, 0x05, 0x39, 0x1f, 0x0f, 0x1d, 0x46, 0x62, 0x51, 0xb6, 0x69, 0xf4, 0x90,
-	0x17, 0x49, 0xcc, 0x53, 0x14, 0xd3, 0x86, 0xe2, 0x56, 0x43, 0x77, 0x20, 0xbe, 0x58, 0xc9, 0xd1,
-	0x2e, 0xe8, 0xd7, 0x8e, 0xc7, 0x79, 0x64, 0x91, 0x92, 0xe8, 0x23, 0xa4, 0x1c, 0x46, 0x1c, 0x21,
-	0x50, 0x1d, 0xca, 0xc3, 0xf0, 0xa6, 0x1f, 0x4e, 0x7c, 0xd9, 0xd4, 0x15, 0xac, 0xf3, 0x2b, 0x9e,
-	0xf8, 0xd6, 0x31, 0x6c, 0xcd, 0x79, 0x76, 0xdb, 0x20, 0x7f, 0x68, 0xb0, 0x75, 0xe2, 0x53, 0xde,
-	0x27, 0xde, 0x5c, 0x94, 0x49, 0x44, 0x5a, 0xee, 0x88, 0x0a, 0x7f, 0x13, 0x51, 0x71, 0x3a, 0xa2,
-	0x24, 0xa7, 0xa5, 0xa9, 0x9c, 0xde, 0x83, 0xb5, 0xa1, 0x4b, 0x9d, 0x0b, 0x8f, 0xf4, 0x2f, 0x83,
-	0xe0, 0x23, 0x95, 0xd3, 0x5b, 0xc1, 0xab, 0xd1, 0xe3, 0xb1, 0x78, 0x43, 0xff, 0x41, 0x55, 0x80,
-	0xe9, 0xd8, 0x19, 0x10, 0x43, 0x97, 0xda, 0xbf, 0x1e, 0xd0, 0xff, 0x00, 0x21, 0x99, 0x50, 0xd2,
-	0x97, 0xe4, 0x65, 0xa9, 0x5f, 0x95, 0x2f, 0x5d, 0xd1, 0x30, 0x27, 0xb0, 0x3d, 0x1f, 0xfc, 0x6d,
-	0x13, 0x89, 0xa1, 0x7e, 0xee, 0xbb, 0xa9, 0x99, 0x4c, 0xeb, 0x97, 0x85, 0xd8, 0x0a, 0x8b, 0xb1,
-	0x59, 0xa7, 0x60, 0x2c, 0x72, 0xde, 0xd2, 0xc1, 0xe6, 0xb7, 0x65, 0x58, 0x8f, 0x47, 0x54, 0x2d,
-	0x3e, 0xe4, 0xc2, 0xea, 0xf4, 0xc6, 0x41, 0x8f, 0xb2, 0xf7, 0xe2, 0xdc, 0x72, 0x37, 0x77, 0xf3,
-	0x40, 0x95, 0xab, 0xd6, 0xd2, 0x53, 0x0d, 0x51, 0xa8, 0xcd, 0xaf, 0x08, 0xb4, 0x97, 0xce, 0x91,
-	0xb1, 0x79, 0x4c, 0x3b, 0x2f, 0x3c, 0x36, 0x8b, 0xae, 0x61, 0x63, 0x61, 0x1f, 0xa0, 0x3f, 0xd2,
-	0xcc, 0x2e, 0x1a, 0xb3, 0x91, 0x1b, 0x9f, 0xd8, 0xfd, 0x00, 0x6b, 0x33, 0xe3, 0x89, 0x32, 0xb2,
-	0x95, 0xb6, 0x5d, 0xcc, 0xc7, 0xb9, 0xb0, 0x89, 0xad, 0x2b, 0x58, 0x9f, 0x6d, 0x61, 0x94, 0x41,
-	0x90, 0x3a, 0xe5, 0xe6, 0x93, 0x7c, 0xe0, 0xc4, 0x1c, 0xaf, 0xe3, 0x7c, 0x4b, 0x66, 0xd5, 0x31,
-	0x63, 0x1c, 0xb2, 0xea, 0x98, 0xd5, 0xe9, 0xd6, 0xd2, 0x3e, 0xbc, 0xad, 0xc4, 0xe8, 0x0b, 0x5d,
-	0xfe, 0xe9, 0x78, 0xfe, 0x33, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x56, 0x6f, 0xa5, 0x0e, 0x09, 0x00,
-	0x00,
+	// 774 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdb, 0x6e, 0xd3, 0x4c,
+	0x10, 0xae, 0x93, 0x34, 0x87, 0xe9, 0x41, 0xe9, 0xfe, 0x6d, 0x93, 0xdf, 0xfa, 0x7f, 0x84, 0x8c,
+	0x80, 0x52, 0xa8, 0x03, 0xe1, 0x1e, 0x29, 0x6d, 0xa3, 0xb6, 0x6a, 0x48, 0xa5, 0x0d, 0x05, 0x89,
+	0x0b, 0x22, 0x37, 0xd9, 0x50, 0x83, 0x6b, 0x07, 0xef, 0xa6, 0xa2, 0x8f, 0xc0, 0x1b, 0x71, 0xc3,
+	0xdb, 0xf0, 0x16, 0xdc, 0xb0, 0x07, 0xaf, 0xc9, 0xc1, 0x06, 0xd3, 0x1b, 0x67, 0x77, 0xe7, 0xdb,
+	0x6f, 0x66, 0xbe, 0x99, 0x9d, 0x16, 0xcc, 0x4b, 0x67, 0xec, 0x36, 0x28, 0x09, 0xaf, 0xdd, 0x01,
+	0xa1, 0x0d, 0xe6, 0x7a, 0x1e, 0x09, 0xed, 0x71, 0x18, 0xb0, 0x00, 0x6d, 0x0a, 0x9b, 0xad, 0x6d,
+	0xb6, 0xb2, 0x99, 0xdb, 0xf2, 0xc6, 0xe0, 0xd2, 0x09, 0x99, 0xfa, 0x2a, 0xb4, 0x59, 0x9b, 0x3e,
+	0x0f, 0xfc, 0x91, 0xfb, 0x3e, 0x32, 0x28, 0x17, 0x21, 0xf1, 0x88, 0x43, 0x89, 0xfe, 0x9d, 0xb9,
+	0xa4, 0x6d, 0xae, 0x3f, 0x0a, 0x94, 0xc1, 0xfa, 0x6e, 0xc0, 0x3f, 0x1d, 0x97, 0x32, 0xac, 0x4c,
+	0x14, 0x93, 0x4f, 0x13, 0x42, 0x19, 0xda, 0x84, 0x65, 0xcf, 0xbd, 0x72, 0x59, 0xdd, 0xb8, 0x6b,
+	0xec, 0xe4, 0xb1, 0xda, 0xa0, 0x6d, 0x28, 0x06, 0xa3, 0x11, 0x25, 0xac, 0x9e, 0xe3, 0xc7, 0x15,
+	0x1c, 0xed, 0xd0, 0x0b, 0x28, 0xd1, 0x20, 0x64, 0xfd, 0x8b, 0x9b, 0x7a, 0x9e, 0x1b, 0xd6, 0x9b,
+	0xf7, 0xed, 0xa4, 0x9c, 0x6c, 0xe1, 0xa9, 0xc7, 0x81, 0xb6, 0xf8, 0xec, 0xdf, 0xe0, 0x22, 0x95,
+	0xbf, 0x82, 0x77, 0xe4, 0x7a, 0x8c, 0x84, 0xf5, 0x82, 0xe2, 0x55, 0x3b, 0x74, 0x04, 0x20, 0x79,
+	0x83, 0x70, 0xc8, 0x6d, 0xcb, 0x92, 0x7a, 0x27, 0x03, 0xf5, 0x99, 0xc0, 0xe3, 0x0a, 0xd5, 0x4b,
+	0xeb, 0x1d, 0x94, 0x35, 0xc0, 0x6a, 0x42, 0x51, 0xb9, 0x47, 0x2b, 0x50, 0x3a, 0xef, 0x9e, 0x76,
+	0xcf, 0xde, 0x74, 0xab, 0x4b, 0xa8, 0x0c, 0x85, 0x6e, 0xeb, 0x65, 0xbb, 0x6a, 0xa0, 0x0d, 0x58,
+	0xeb, 0xb4, 0x7a, 0xaf, 0xfa, 0xb8, 0xdd, 0x69, 0xb7, 0x7a, 0xed, 0xc3, 0x6a, 0xce, 0xba, 0x03,
+	0x95, 0x98, 0x17, 0x95, 0x20, 0xdf, 0xea, 0x1d, 0xa8, 0x2b, 0x87, 0x6d, 0xbe, 0x32, 0xac, 0x2f,
+	0x06, 0x6c, 0xce, 0xca, 0x48, 0xc7, 0x81, 0x4f, 0x89, 0xd0, 0x71, 0x10, 0x4c, 0xfc, 0x58, 0x47,
+	0xb9, 0x41, 0x08, 0x0a, 0x3e, 0xf9, 0xac, 0x55, 0x94, 0x6b, 0x81, 0x64, 0x01, 0x73, 0x3c, 0xa9,
+	0x20, 0x47, 0xca, 0x0d, 0x7a, 0x06, 0xe5, 0xa8, 0x6a, 0x94, 0x6b, 0x93, 0xdf, 0x59, 0x69, 0x6e,
+	0xa9, 0xfc, 0x75, 0x7d, 0x23, 0x8f, 0x38, 0x86, 0x59, 0x7b, 0x50, 0x3b, 0x22, 0x3a, 0x92, 0x1e,
+	0x73, 0xd8, 0x24, 0xae, 0xaa, 0xf0, 0xeb, 0x5c, 0x11, 0x19, 0x8c, 0xf0, 0xcb, 0xd7, 0xd6, 0x6b,
+	0xa8, 0x2f, 0xc2, 0xa3, 0xe8, 0x13, 0xf0, 0xe8, 0x01, 0x14, 0x44, 0xff, 0xc8, 0xd8, 0x57, 0x9a,
+	0x68, 0x36, 0x9a, 0x13, 0x6e, 0xc1, 0xd2, 0x6e, 0xd9, 0xd3, 0xbc, 0x07, 0x81, 0xcf, 0x88, 0xcf,
+	0x7e, 0x17, 0x47, 0x07, 0xfe, 0x4d, 0xc0, 0x47, 0x81, 0x34, 0xa0, 0x14, 0xb9, 0x90, 0x77, 0x52,
+	0x55, 0xd0, 0x28, 0xeb, 0x1b, 0x2f, 0xc8, 0xf9, 0x78, 0xe8, 0x30, 0xa2, 0x4d, 0xe9, 0xae, 0xd1,
+	0x43, 0x5e, 0x24, 0xf1, 0x9e, 0xa2, 0x9c, 0x36, 0x14, 0xb7, 0x7a, 0x74, 0x07, 0xe2, 0x8b, 0x95,
+	0x1d, 0xed, 0x42, 0xf1, 0xda, 0xf1, 0x38, 0x8f, 0x2c, 0x52, 0x9c, 0x7d, 0x84, 0x94, 0x8f, 0x11,
+	0x47, 0x08, 0x54, 0x83, 0xd2, 0x30, 0xbc, 0xe9, 0x87, 0x13, 0x5f, 0x36, 0x75, 0x19, 0x17, 0xf9,
+	0x16, 0x4f, 0x7c, 0x74, 0x0f, 0xd6, 0x86, 0x2e, 0x75, 0x2e, 0x3c, 0xd2, 0xbf, 0x0c, 0x82, 0x8f,
+	0x54, 0xf6, 0x75, 0x19, 0xaf, 0x46, 0x87, 0xc7, 0xe2, 0xcc, 0x3a, 0x86, 0xad, 0xb9, 0xf0, 0x6f,
+	0xab, 0xc4, 0x0f, 0x03, 0xb6, 0x4e, 0x7c, 0xca, 0x9b, 0xc9, 0x9b, 0x93, 0x22, 0x4e, 0xdb, 0xc8,
+	0x9c, 0x76, 0xee, 0x6f, 0xd2, 0xce, 0xcf, 0xa4, 0xad, 0x85, 0x2f, 0x4c, 0x09, 0x9f, 0x45, 0x0a,
+	0xf4, 0x1f, 0x54, 0x04, 0x98, 0x8e, 0x9d, 0x01, 0xa9, 0x17, 0xe5, 0xed, 0x5f, 0x07, 0xe8, 0x7f,
+	0x80, 0x90, 0x4c, 0x28, 0xe9, 0x4b, 0xf2, 0x92, 0xbc, 0x5f, 0x91, 0x27, 0x5d, 0xd1, 0x55, 0x27,
+	0xb0, 0x3d, 0x9f, 0xfc, 0x6d, 0x85, 0xc4, 0x50, 0x3b, 0xf7, 0xdd, 0x44, 0x25, 0x93, 0x9a, 0x6a,
+	0x21, 0xb7, 0x5c, 0x42, 0x99, 0x4f, 0xa1, 0xbe, 0xc8, 0x79, 0xcb, 0x00, 0x9b, 0x5f, 0x97, 0x61,
+	0x5d, 0xbf, 0x63, 0x35, 0x1d, 0x91, 0x0b, 0xab, 0xd3, 0x63, 0x09, 0x3d, 0x4a, 0x1f, 0x9e, 0x73,
+	0x7f, 0x01, 0xcc, 0xdd, 0x2c, 0x50, 0x15, 0xaa, 0xb5, 0xf4, 0xd4, 0x40, 0x14, 0xaa, 0xf3, 0x73,
+	0x04, 0xed, 0x25, 0x73, 0xa4, 0x8c, 0x27, 0xd3, 0xce, 0x0a, 0xd7, 0x6e, 0xd1, 0x35, 0x6c, 0x2c,
+	0x0c, 0x0d, 0xf4, 0x47, 0x9a, 0xd9, 0x69, 0x64, 0x36, 0x32, 0xe3, 0x63, 0xbf, 0x1f, 0x60, 0x6d,
+	0xe6, 0x79, 0xa2, 0x14, 0xb5, 0x92, 0x46, 0x90, 0xf9, 0x38, 0x13, 0x36, 0xf6, 0x75, 0x05, 0xeb,
+	0xb3, 0x2d, 0x8c, 0x52, 0x08, 0x12, 0x5f, 0xb9, 0xf9, 0x24, 0x1b, 0x38, 0x76, 0xc7, 0xeb, 0x38,
+	0xdf, 0x92, 0x69, 0x75, 0x4c, 0x79, 0x0e, 0x69, 0x75, 0x4c, 0xeb, 0x74, 0x6b, 0x69, 0x1f, 0xde,
+	0x96, 0x35, 0xfa, 0xa2, 0x28, 0xff, 0x33, 0x79, 0xfe, 0x33, 0x00, 0x00, 0xff, 0xff, 0x97, 0xd7,
+	0x36, 0xd6, 0x33, 0x09, 0x00, 0x00,
 }
diff --git a/pkg/repo/repo.go b/pkg/repo/repo.go
index f8b4267f4b123ebbdc3ea54c76a3128e4f00a30f..c4ed13c52162044ed3953b8ecec9595bcedd5fc5 100644
--- a/pkg/repo/repo.go
+++ b/pkg/repo/repo.go
@@ -98,8 +98,7 @@ func LoadChartRepository(dir, url string) (*ChartRepository, error) {
 					return nil
 				}
 				r.IndexFile = i
-			} else {
-				// TODO: check for tgz extension
+			} else if strings.HasSuffix(f.Name(), ".tgz") {
 				r.ChartPaths = append(r.ChartPaths, path)
 			}
 		}