[gitg] Better handling of command line args and repository paths



commit 0c14b150e1999e23df31e614c5da6224302aecc0
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Sat May 29 18:00:56 2010 +0200

    Better handling of command line args and repository paths

 gitg/gitg-branch-actions.c    |   25 ++-
 gitg/gitg-commit.c            |   58 ++++--
 gitg/gitg-config.c            |   86 +++++++--
 gitg/gitg-dnd.c               |   12 +-
 gitg/gitg-repository-dialog.c |    7 +-
 gitg/gitg-repository.c        |  286 +++++++++++++++++++---------
 gitg/gitg-repository.h        |   11 +-
 gitg/gitg-runner.c            |   54 +++---
 gitg/gitg-runner.h            |   33 ++--
 gitg/gitg-utils.c             |  108 +++++------
 gitg/gitg-utils.h             |    3 +-
 gitg/gitg-window.c            |  423 ++++++++++++++++++++++++----------------
 gitg/gitg-window.h            |   20 ++-
 gitg/gitg.c                   |   50 +++--
 14 files changed, 743 insertions(+), 433 deletions(-)
---
diff --git a/gitg/gitg-branch-actions.c b/gitg/gitg-branch-actions.c
index d9743f0..4d207de 100644
--- a/gitg/gitg-branch-actions.c
+++ b/gitg/gitg-branch-actions.c
@@ -792,14 +792,13 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
 
 	close (fd);
 
-	gchar const *gitdir = gitg_repository_get_path (repository);
-	gchar *indexpath = g_build_filename (gitdir, ".git", "index", NULL);
+	GFile *git_dir = gitg_repository_get_git_dir (repository);
+	GFile *index_ = g_file_get_child (git_dir, "index");
 
-	GFile *index = g_file_new_for_path (indexpath);
-	g_free (indexpath);
+	gboolean copied = g_file_copy (index_, customindex, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
 
-	gboolean copied = g_file_copy (index, customindex, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
-	g_object_unref (index);
+	g_object_unref (index_);
+	g_object_unref (git_dir);
 
 	if (!copied)
 	{
@@ -862,18 +861,26 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
 		*ref = g_strdup (rref);
 	}
 
-	// Make ref
-	gchar *path = g_build_filename (gitg_repository_get_path (repository),
-	                                ".git",
+	git_dir = gitg_repository_get_git_dir (repository);
+	gchar *git_path = g_file_get_path (git_dir);
+
+	gchar *path = g_build_filename (git_path,
 	                                "logs",
 	                                "refs",
 	                                "stash",
 	                                NULL);
+
+	g_object_unref (git_dir);
+	g_free (git_path);
+
 	GFile *reflog = g_file_new_for_path (path);
 	GFileOutputStream *stream = g_file_create (reflog, G_FILE_CREATE_NONE, NULL, NULL);
+
 	g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
+
 	g_object_unref (stream);
 	g_object_unref (reflog);
+
 	g_free (path);
 
 	gitg_repository_run_commandv (repository, runner, NULL,
diff --git a/gitg/gitg-commit.c b/gitg/gitg-commit.c
index 5c96c91..400d5ca 100644
--- a/gitg/gitg-commit.c
+++ b/gitg/gitg-commit.c
@@ -273,12 +273,13 @@ add_files(GitgCommit *commit, gchar **buffer, gboolean cached)
 		gchar const *mode = parts[0] + 1;
 		gchar const *sha = parts[2];
 
-		gchar *path = g_build_filename(gitg_repository_get_path(commit->priv->repository), parts[5], NULL);
+		GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository);
+		GFile *file = g_file_get_child (work_tree, parts[5]);
 
-		GFile *file = g_file_new_for_path(path);
-		g_free(path);
+		g_object_unref (work_tree);
 
-		GitgChangedFile *f = GITG_CHANGED_FILE(g_hash_table_lookup(commit->priv->files, file));
+		GitgChangedFile *f = GITG_CHANGED_FILE (g_hash_table_lookup (commit->priv->files,
+		                                                             file));
 
 		if (f)
 		{
@@ -398,10 +399,11 @@ read_other_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
 			continue;
 
 		/* Check if file is already in our index */
-		gchar *path = g_build_filename(gitg_repository_get_path(commit->priv->repository), line, NULL);
+		GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository);
+		GFile *file = g_file_get_child (work_tree, line);
+
+		g_object_unref (work_tree);
 
-		GFile *file = g_file_new_for_path(path);
-		g_free(path);
 		GitgChangedFile *f = g_hash_table_lookup(commit->priv->files, file);
 
 		if (f)
@@ -916,10 +918,13 @@ gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, g
 	if (!write_tree(commit, &tree, error))
 		return FALSE;
 
-	gchar *path = g_build_filename (gitg_repository_get_path (commit->priv->repository),
-	                                ".git",
-	                                "COMMIT_EDITMSG",
-	                                NULL);
+	GFile *git_dir = gitg_repository_get_git_dir (commit->priv->repository);
+	GFile *child = g_file_get_child (git_dir, "COMMIT_EDITMSG");
+	gchar *path = g_file_get_path (child);
+
+	g_object_unref (git_dir);
+	g_object_unref (child);
+
 	g_file_set_contents (path, comment, -1, NULL);\
 	g_free (path);
 
@@ -983,7 +988,15 @@ gitg_commit_revert(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk,
 		GitgRunner *runner = gitg_runner_new_synchronized(1000);
 		gchar const *argv[] = {"patch", "-p1", "-R", NULL};
 
-		ret = gitg_runner_run_with_arguments(runner, argv, gitg_repository_get_path(commit->priv->repository), hunk, NULL); 
+		GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository);
+
+		ret = gitg_runner_run_with_arguments (runner,
+		                                      work_tree,
+		                                      argv,
+		                                      hunk,
+		                                      NULL);
+
+		g_object_unref (work_tree);
 
 		update_index_file(commit, file);
 		update_index_unstaged(commit, file);
@@ -994,21 +1007,24 @@ gitg_commit_revert(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk,
 	return ret;
 }
 
-gboolean 
-gitg_commit_add_ignore(GitgCommit *commit, GitgChangedFile *file, GError **error)
+gboolean
+gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **error)
 {
-	g_return_val_if_fail(GITG_IS_COMMIT(commit), FALSE);
-	g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), FALSE);
+	g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
+	g_return_val_if_fail (GITG_IS_CHANGED_FILE (file), FALSE);
 
-	GFile *f = gitg_changed_file_get_file(file);
-	gchar *path = gitg_repository_relative(commit->priv->repository, f);
+	GFile *f = gitg_changed_file_get_file (file);
+	gchar *path = gitg_repository_relative (commit->priv->repository, f);
 
-	gchar *ignore = g_strdup_printf("%s/.gitignore", gitg_repository_get_path(commit->priv->repository));
-	GFile *ig = g_file_new_for_path(ignore);
+	GFile *git_dir = gitg_repository_get_work_tree (commit->priv->repository);
+	GFile *ignore = g_file_get_child (git_dir, ".gitignore");
 
-	GFileOutputStream *stream = g_file_append_to(ig, G_FILE_CREATE_NONE, NULL, error);
+	GFileOutputStream *stream = g_file_append_to (ignore, G_FILE_CREATE_NONE, NULL, error);
 	gboolean ret = FALSE;
 
+	g_object_unref (git_dir);
+	g_object_unref (ignore);
+
 	if (stream)
 	{
 		gchar *line = g_strdup_printf("/%s\n", path);
diff --git a/gitg/gitg-config.c b/gitg/gitg-config.c
index 84514a2..c68cddd 100644
--- a/gitg/gitg-config.c
+++ b/gitg/gitg-config.c
@@ -213,8 +213,14 @@ static gchar *
 get_value_local (GitgConfig *config, gchar const *key)
 {
 	gboolean ret;
-	gchar const *path = gitg_repository_get_path (config->priv->repository);
-	gchar *cfg = g_build_filename (path, ".git", "config", NULL);
+	GFile *git_dir;
+	GFile *cfg_file;
+	gchar *cfg;
+
+	git_dir = gitg_repository_get_git_dir (config->priv->repository);
+
+	cfg_file = g_file_get_child (git_dir, "config");
+	cfg = g_file_get_path (cfg_file);
 
 	ret = gitg_repository_run_commandv (config->priv->repository, 
 	                                    config->priv->runner,
@@ -224,8 +230,12 @@ get_value_local (GitgConfig *config, gchar const *key)
 	                                    cfg,
 	                                    key,
 	                                    NULL);
+
 	g_free (cfg);
 
+	g_object_unref (cfg_file);
+	g_object_unref (git_dir);
+
 	return get_value_process (config, ret);
 }
 
@@ -233,8 +243,14 @@ static gchar *
 get_value_local_regex (GitgConfig *config, gchar const *regex)
 {
 	gboolean ret;
-	gchar const *path = gitg_repository_get_path (config->priv->repository);
-	gchar *cfg = g_build_filename (path, ".git", "config", NULL);
+	GFile *git_dir;
+	GFile *cfg_file;
+	gchar *cfg;
+
+	git_dir = gitg_repository_get_git_dir (config->priv->repository);
+
+	cfg_file = g_file_get_child (git_dir, "config");
+	cfg = g_file_get_path (cfg_file);
 
 	ret = gitg_repository_run_commandv (config->priv->repository, 
 	                                    config->priv->runner,
@@ -245,8 +261,12 @@ get_value_local_regex (GitgConfig *config, gchar const *regex)
 	                                    "--get-regexp",
 	                                    regex,
 	                                    NULL);
+
 	g_free (cfg);
 
+	g_object_unref (cfg_file);
+	g_object_unref (git_dir);
+
 	return get_value_process (config, ret);
 }
 
@@ -268,10 +288,17 @@ set_value_global (GitgConfig *config, gchar const *key, gchar const *value)
 static gboolean
 set_value_local (GitgConfig *config, gchar const *key, gchar const *value)
 {
-	gchar const *path = gitg_repository_get_path (config->priv->repository);
-	gchar *cfg = g_build_filename (path, ".git", "config", NULL);
+	gboolean ret;
+	GFile *git_dir;
+	GFile *cfg_file;
+	gchar *cfg;
 
-	return gitg_repository_run_commandv (config->priv->repository, 
+	git_dir = gitg_repository_get_git_dir (config->priv->repository);
+
+	cfg_file = g_file_get_child (git_dir, "config");
+	cfg = g_file_get_path (cfg_file);
+
+	ret = gitg_repository_run_commandv (config->priv->repository,
 	                                     config->priv->runner,
 	                                     NULL,
 	                                     "config",
@@ -280,6 +307,13 @@ set_value_local (GitgConfig *config, gchar const *key, gchar const *value)
 	                                     value == NULL ? "--unset" : key,
 	                                     value == NULL ? key : value,
 	                                     NULL);
+
+	g_free (cfg);
+
+	g_object_unref (cfg_file);
+	g_object_unref (git_dir);
+
+	return ret;
 }
 
 static gboolean
@@ -301,19 +335,33 @@ rename_global (GitgConfig *config, gchar const *old, gchar const *nw)
 static gboolean
 rename_local (GitgConfig *config, gchar const *old, gchar const *nw)
 {
-	gchar const *path = gitg_repository_get_path (config->priv->repository);
-	gchar *cfg = g_build_filename (path, ".git", "config", NULL);
+	gboolean ret;
+	GFile *git_dir;
+	GFile *cfg_file;
+	gchar *cfg;
 
-	return gitg_repository_run_commandv (config->priv->repository, 
-	                                     config->priv->runner,
-	                                     NULL,
-	                                     "config",
-	                                     "--file",
-	                                     cfg,
-	                                     "--rename-section",
-	                                     old,
-	                                     nw,
-	                                     NULL);
+	git_dir = gitg_repository_get_git_dir (config->priv->repository);
+
+	cfg_file = g_file_get_child (git_dir, "config");
+	cfg = g_file_get_path (cfg_file);
+
+	ret = gitg_repository_run_commandv (config->priv->repository, 
+	                                    config->priv->runner,
+	                                    NULL,
+	                                    "config",
+	                                    "--file",
+	                                    cfg,
+	                                    "--rename-section",
+	                                    old,
+	                                    nw,
+	                                    NULL);
+
+	g_free (cfg);
+
+	g_object_unref (cfg_file);
+	g_object_unref (git_dir);
+
+	return ret;
 }
 
 gchar *
diff --git a/gitg/gitg-dnd.c b/gitg/gitg-dnd.c
index 312fc2a..acb10f5 100644
--- a/gitg/gitg-dnd.c
+++ b/gitg/gitg-dnd.c
@@ -785,11 +785,15 @@ static gchar *
 revision_to_uri (GitgRepository *repository,
                  GitgRevision   *revision)
 {
-	gchar const *path = gitg_repository_get_path (repository);
+	GFile *work_tree = gitg_repository_get_work_tree (repository);
 	gchar *sha1 = gitg_revision_get_sha1 (revision);
 
+	gchar *path = g_file_get_path (work_tree);
 	gchar *ret = g_strdup_printf ("gitg://%s:%s", path, sha1);
+
 	g_free (sha1);
+	g_free (path);
+	g_object_unref (work_tree);
 
 	return ret;
 }
@@ -798,11 +802,15 @@ static gchar *
 revision_to_treeish (GitgRepository *repository,
                      GitgRevision   *revision)
 {
-	gchar const *path = gitg_repository_get_path (repository);
+	GFile *work_tree = gitg_repository_get_work_tree (repository);
 	gchar *sha1 = gitg_revision_get_sha1 (revision);
+	gchar *path = g_file_get_path (work_tree);
 
 	gchar *ret = g_strdup_printf ("%s\n%s", path, sha1);
+
 	g_free (sha1);
+	g_free (path);
+	g_object_unref (work_tree);
 
 	return ret;
 }
diff --git a/gitg/gitg-repository-dialog.c b/gitg/gitg-repository-dialog.c
index 9de419d..504f222 100644
--- a/gitg/gitg-repository-dialog.c
+++ b/gitg/gitg-repository-dialog.c
@@ -486,10 +486,13 @@ create_repository_dialog (GitgWindow *window)
 	gtk_builder_connect_signals(b, repository_dialog);
 	g_object_unref (b);
 
-	gchar *basename = g_path_get_basename(gitg_repository_get_path(repository));
-	gchar *title = g_strdup_printf("%s - %s", _("Properties"), basename);
+	GFile *work_tree = gitg_repository_get_work_tree (repository);
+	gchar *basename = g_file_get_basename (work_tree);
+	g_object_unref (work_tree);
 
+	gchar *title = g_strdup_printf("%s - %s", _("Properties"), basename);
 	gtk_window_set_title(GTK_WINDOW(repository_dialog), title);
+
 	g_free (title);
 	g_free (basename);
 
diff --git a/gitg/gitg-repository.c b/gitg/gitg-repository.c
index db0a55c..165b608 100644
--- a/gitg/gitg-repository.c
+++ b/gitg/gitg-repository.c
@@ -47,7 +47,8 @@ enum
 {
 	PROP_0,
 
-	PROP_PATH,
+	PROP_WORK_TREE,
+	PROP_GIT_DIR,
 	PROP_LOADER
 };
 
@@ -82,7 +83,9 @@ typedef enum
 
 struct _GitgRepositoryPrivate
 {
-	gchar *path;
+	GFile *git_dir;
+	GFile *work_tree;
+
 	GitgRunner *loader;
 	GHashTable *hashtable;
 	gint stamp;
@@ -363,8 +366,15 @@ gitg_repository_finalize(GObject *object)
 	/* Clear the model to remove all revision objects */
 	do_clear(rp, FALSE);
 
-	/* Free the path */
-	g_free(rp->priv->path);
+	if (rp->priv->work_tree)
+	{
+		g_object_unref (rp->priv->work_tree);
+	}
+
+	if (rp->priv->git_dir)
+	{
+		g_object_unref (rp->priv->git_dir);
+	}
 
 	/* Free the hash */
 	g_hash_table_destroy(rp->priv->hashtable);
@@ -405,9 +415,21 @@ gitg_repository_set_property(GObject *object, guint prop_id, GValue const *value
 
 	switch (prop_id)
 	{
-		case PROP_PATH:
-			g_free(self->priv->path);
-			self->priv->path = gitg_utils_find_git(g_value_get_string(value));
+		case PROP_WORK_TREE:
+			if (self->priv->work_tree)
+			{
+				g_object_unref (self->priv->work_tree);
+			}
+
+			self->priv->work_tree = g_value_dup_object (value);
+		break;
+		case PROP_GIT_DIR:
+			if (self->priv->git_dir)
+			{
+				g_object_unref (self->priv->git_dir);
+			}
+
+			self->priv->git_dir = g_value_dup_object (value);
 		break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -422,8 +444,12 @@ gitg_repository_get_property(GObject *object, guint prop_id, GValue *value, GPar
 
 	switch (prop_id)
 	{
-		case PROP_PATH:
-			g_value_set_string(value, self->priv->path);
+		case PROP_WORK_TREE:
+			g_value_set_object (value, self->priv->work_tree);
+		break;
+		case PROP_GIT_DIR:
+			g_value_set_object (value, self->priv->git_dir);
+		break;
 		break;
 		case PROP_LOADER:
 			g_value_set_object(value, self->priv->loader);
@@ -437,7 +463,13 @@ gitg_repository_get_property(GObject *object, guint prop_id, GValue *value, GPar
 static gchar *
 parse_ref_intern (GitgRepository *repository, gchar const *ref, gboolean symbolic)
 {
-	gchar **ret = gitg_repository_command_with_outputv(repository, NULL, "rev-parse", "--verify", symbolic ? "--symbolic-full-name" : ref, symbolic ? ref : NULL, NULL);
+	gchar **ret = gitg_repository_command_with_outputv (repository,
+	                                                    NULL,
+	                                                    "rev-parse",
+	                                                    "--verify",
+	                                                    symbolic ? "--symbolic-full-name" : ref,
+	                                                    symbolic ? ref : NULL,
+	                                                    NULL);
 
 	if (!ret)
 		return NULL;
@@ -498,35 +530,43 @@ on_head_changed (GFileMonitor      *monitor,
 static void
 install_head_monitor (GitgRepository *repository)
 {
-	gchar *path = g_build_filename (repository->priv->path, ".git", "HEAD", NULL);
-	GFile *file = g_file_new_for_path (path);
+	GFile *file = g_file_get_child (repository->priv->git_dir, "HEAD");
 
-	repository->priv->monitor = g_file_monitor_file (file, 
+	repository->priv->monitor = g_file_monitor_file (file,
 	                                                 G_FILE_MONITOR_NONE,
 	                                                 NULL,
 	                                                 NULL);
 
-	g_signal_connect (repository->priv->monitor, 
-	                  "changed", 
+	g_signal_connect (repository->priv->monitor,
+	                  "changed",
 	                  G_CALLBACK (on_head_changed),
 	                  repository);
 
-	g_free (path);
 	g_object_unref (file);
 }
 
-static GObject *
-gitg_repository_constructor (GType                  type,
-                             guint                  n_construct_properties,
-                             GObjectConstructParam *construct_properties)
+static void
+gitg_repository_constructed (GObject *object)
 {
-	GObject *ret = G_OBJECT_CLASS (gitg_repository_parent_class)->constructor (type,
-	                                                                           n_construct_properties,
-	                                                                           construct_properties);
+	GitgRepository *repository = GITG_REPOSITORY (object);
 
-	install_head_monitor (GITG_REPOSITORY (ret));
+	if (repository->priv->git_dir == NULL &&
+	    repository->priv->work_tree == NULL)
+	{
+		return;
+	}
 
-	return ret;
+	if (repository->priv->git_dir == NULL)
+	{
+		repository->priv->git_dir = g_file_get_child (repository->priv->work_tree,
+		                                              ".git");
+	}
+	else if (repository->priv->work_tree == NULL)
+	{
+		repository->priv->work_tree = g_file_get_parent (repository->priv->git_dir);
+	}
+
+	install_head_monitor (repository);
 }
 
 static void 
@@ -538,21 +578,31 @@ gitg_repository_class_init(GitgRepositoryClass *klass)
 	object_class->set_property = gitg_repository_set_property;
 	object_class->get_property = gitg_repository_get_property;
 
-	object_class->constructor = gitg_repository_constructor;
-
-	g_object_class_install_property(object_class, PROP_PATH,
-						 g_param_spec_string ("path",
-								      "PATH",
-								      "The repository path",
-								      NULL,
-								      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property(object_class, PROP_LOADER,
-						 g_param_spec_object ("loader",
-								      "LOADER",
-								      "The repository loader",
-								      GITG_TYPE_RUNNER,
-								      G_PARAM_READABLE));
+	object_class->constructed = gitg_repository_constructed;
+
+	g_object_class_install_property (object_class,
+	                                 PROP_GIT_DIR,
+	                                 g_param_spec_object ("git-dir",
+	                                                      "GIT_DIR",
+	                                                      "The repository .git directory",
+	                                                      G_TYPE_FILE,
+	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (object_class,
+	                                 PROP_WORK_TREE,
+	                                 g_param_spec_object ("work-tree",
+	                                                      "WORK_TREE",
+	                                                      "The work tree directory",
+	                                                      G_TYPE_FILE,
+	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (object_class,
+	                                 PROP_LOADER,
+	                                 g_param_spec_object ("loader",
+	                                                      "LOADER",
+	                                                      "The repository loader",
+	                                                      GITG_TYPE_RUNNER,
+	                                                      G_PARAM_READABLE));
 
 	repository_signals[LOAD] =
 		g_signal_new ("load",
@@ -816,7 +866,6 @@ repository_relane(GitgRepository *repository)
 	GtkTreeIter iter;
 	GtkTreePath *path = gtk_tree_path_new_first();
 
-
 	for (i = 0; i < repository->priv->size; ++i)
 	{
 		gint8 mylane;
@@ -1090,17 +1139,28 @@ grow_storage(GitgRepository *repository, gint size)
 }
 
 GitgRepository *
-gitg_repository_new(gchar const *path)
+gitg_repository_new (GFile *git_dir, GFile *work_tree)
 {
-	return g_object_new(GITG_TYPE_REPOSITORY, "path", path, NULL);
+	return g_object_new (GITG_TYPE_REPOSITORY,
+	                     "git-dir", git_dir,
+	                     "work-tree", work_tree,
+	                     NULL);
 }
 
-gchar const *
-gitg_repository_get_path(GitgRepository *self)
+GFile *
+gitg_repository_get_work_tree (GitgRepository *self)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(self), NULL);
+	g_return_val_if_fail (GITG_IS_REPOSITORY(self), NULL);
+
+	return g_file_dup (self->priv->work_tree);
+}
+
+GFile *
+gitg_repository_get_git_dir (GitgRepository *self)
+{
+	g_return_val_if_fail (GITG_IS_REPOSITORY (self), NULL);
 
-	return self->priv->path;
+	return g_file_dup (self->priv->git_dir);
 }
 
 GitgRunner *
@@ -1211,24 +1271,24 @@ load_refs(GitgRepository *self)
 void
 gitg_repository_reload(GitgRepository *repository)
 {
-	g_return_if_fail(GITG_IS_REPOSITORY(repository));
-	g_return_if_fail(repository->priv->path != NULL);
+	g_return_if_fail (GITG_IS_REPOSITORY (repository));
+	g_return_if_fail (repository->priv->git_dir != NULL);
 
-	gitg_runner_cancel(repository->priv->loader);
+	gitg_runner_cancel (repository->priv->loader);
 
 	repository->priv->load_stage = LOAD_STAGE_NONE;
-	gitg_repository_clear(repository);
+	gitg_repository_clear (repository);
 
-	load_refs(repository);
-	reload_revisions(repository, NULL);
+	load_refs (repository);
+	reload_revisions (repository, NULL);
 }
 
 gboolean
-gitg_repository_load(GitgRepository *self, int argc, gchar const **av, GError **error)
+gitg_repository_load (GitgRepository *self, int argc, gchar const **av, GError **error)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(self), FALSE);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (self), FALSE);
 
-	if (self->priv->path == NULL)
+	if (self->priv->git_dir == NULL)
 	{
 		if (error)
 		{
@@ -1361,70 +1421,104 @@ gitg_repository_get_current_ref(GitgRepository *repository)
 }
 
 gchar *
-gitg_repository_relative(GitgRepository *repository, GFile *file)
+gitg_repository_relative (GitgRepository *repository, GFile *file)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), NULL);
-	g_return_val_if_fail(repository->priv->path != NULL, NULL);
-
-	GFile *parent = g_file_new_for_path(repository->priv->path);
-	gchar *ret = g_file_get_relative_path(parent, file);
-	g_object_unref(parent);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL);
+	g_return_val_if_fail (repository->priv->work_tree != NULL, NULL);
 
-	return ret;
+	return g_file_get_relative_path (repository->priv->work_tree, file);
 }
 
 gboolean
-gitg_repository_run_command_with_input(GitgRepository *repository, GitgRunner *runner, gchar const **argv, gchar const *input, GError **error)
+gitg_repository_run_command_with_input (GitgRepository *repository,
+                                        GitgRunner *runner,
+                                        gchar const **argv,
+                                        gchar const *input,
+                                        GError **error)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), FALSE);
-	g_return_val_if_fail(GITG_IS_RUNNER(runner), FALSE);
-	g_return_val_if_fail(repository->priv->path != NULL, FALSE);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+	g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
+	g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
 
-	guint num = g_strv_length((gchar **)argv);
+	guint num = g_strv_length ((gchar **)argv);
 	guint i;
-	gchar const **args = g_new0(gchar const *, num + 2);
+
+	gchar const **args = g_new0 (gchar const *, num + 6);
+
+	gchar *git_dir_path = g_file_get_path (repository->priv->git_dir);
+	gchar *work_tree_path = g_file_get_path (repository->priv->work_tree);
+
 	args[0] = "git";
+	args[1] = "--git-dir";
+	args[2] = git_dir_path;
+	args[3] = "--work-tree";
+	args[4] = work_tree_path;
 
 	for (i = 0; i < num; ++i)
-		args[i + 1] = argv[i];
+	{
+		args[i + 5] = argv[i];
+	}
+
+	gboolean ret = gitg_runner_run_with_arguments (runner,
+	                                               repository->priv->work_tree,
+	                                               args,
+	                                               input,
+	                                               error);
 
-	gboolean ret = gitg_runner_run_with_arguments(runner, args, repository->priv->path, input, error);
-	g_free(args);
+	g_free (args);
+	g_free (git_dir_path);
+	g_free (work_tree_path);
 
 	return ret;
 }
 
 gboolean
-gitg_repository_run_command(GitgRepository *repository, GitgRunner *runner, gchar const **argv, GError **error)
+gitg_repository_run_command (GitgRepository *repository,
+                             GitgRunner *runner,
+                             gchar const **argv,
+                             GError **error)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), FALSE);
-	g_return_val_if_fail(GITG_IS_RUNNER(runner), FALSE);
-	g_return_val_if_fail(repository->priv->path != NULL, FALSE);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+	g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
+	g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
 
-	return gitg_repository_run_command_with_input(repository, runner, argv, NULL, error);
+	return gitg_repository_run_command_with_input (repository,
+	                                               runner,
+	                                               argv,
+	                                               NULL,
+	                                               error);
 }
 
 gboolean 
-gitg_repository_command_with_input(GitgRepository *repository, gchar const **argv, gchar const *input, GError **error)
+gitg_repository_command_with_input (GitgRepository *repository,
+                                    gchar const **argv,
+                                    gchar const *input,
+                                    GError **error)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), FALSE);
-	g_return_val_if_fail(repository->priv->path != NULL, FALSE);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+	g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
 
-	GitgRunner *runner = gitg_runner_new_synchronized(1000);
+	GitgRunner *runner = gitg_runner_new_synchronized (1000);
 
-	gboolean ret = gitg_repository_run_command_with_input(repository, runner, argv, input, error);
+	gboolean ret = gitg_repository_run_command_with_input (repository,
+	                                                       runner,
+	                                                       argv,
+	                                                       input,
+	                                                       error);
 	g_object_unref(runner);
 
 	return ret;
 }
 
 gboolean
-gitg_repository_command(GitgRepository *repository, gchar const **argv, GError **error)
+gitg_repository_command (GitgRepository *repository,
+                         gchar const **argv,
+                         GError **error)
 {
-	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), FALSE);
-	g_return_val_if_fail(repository->priv->path != NULL, FALSE);
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+	g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
 
-	return gitg_repository_command_with_input(repository, argv, NULL, error);
+	return gitg_repository_command_with_input (repository, argv, NULL, error);
 }
 
 typedef struct
@@ -1452,7 +1546,7 @@ gchar **
 gitg_repository_command_with_input_and_output(GitgRepository *repository, gchar const **argv, gchar const *input, GError **error)
 {
 	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), NULL);
-	g_return_val_if_fail(repository->priv->path != NULL, NULL);
+	g_return_val_if_fail(repository->priv->git_dir != NULL, NULL);
 
 	GitgRunner *runner = gitg_runner_new_synchronized(1000);
 	CommandOutput output = {NULL, 0};
@@ -1474,7 +1568,7 @@ gchar **
 gitg_repository_command_with_output(GitgRepository *repository, gchar const **argv, GError **error)
 {
 	g_return_val_if_fail(GITG_IS_REPOSITORY(repository), NULL);
-	g_return_val_if_fail(repository->priv->path != NULL, NULL);
+	g_return_val_if_fail(repository->priv->git_dir != NULL, NULL);
 
 	return gitg_repository_command_with_input_and_output(repository, argv, NULL, error);
 }
@@ -1670,3 +1764,17 @@ gitg_repository_get_current_selection (GitgRepository *repository)
 
 	return (gchar const **)repository->priv->selection;
 }
+
+gboolean
+gitg_repository_exists (GitgRepository *repository)
+{
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+
+	if (repository->priv->git_dir == NULL)
+	{
+		return FALSE;
+	}
+
+	return g_file_query_exists (repository->priv->git_dir, NULL) &&
+	       g_file_query_exists (repository->priv->work_tree, NULL);
+}
diff --git a/gitg/gitg-repository.h b/gitg/gitg-repository.h
index 8f8f55e..a678b61 100644
--- a/gitg/gitg-repository.h
+++ b/gitg/gitg-repository.h
@@ -65,8 +65,15 @@ struct _GitgRepositoryClass
 };
 
 GType gitg_repository_get_type (void) G_GNUC_CONST;
-GitgRepository *gitg_repository_new(gchar const *path);
-gchar const *gitg_repository_get_path(GitgRepository *repository);
+
+GitgRepository *gitg_repository_new (GFile *git_dir,
+                                     GFile *work_tree);
+
+GFile *gitg_repository_get_work_tree (GitgRepository *repository);
+GFile *gitg_repository_get_git_dir (GitgRepository *repository);
+
+gboolean gitg_repository_exists (GitgRepository *repository);
+
 GitgRunner *gitg_repository_get_loader(GitgRepository *repository);
 
 gboolean gitg_repository_load(GitgRepository *repository, int argc, gchar const **argv, GError **error);
diff --git a/gitg/gitg-runner.c b/gitg/gitg-runner.c
index ec4244e..c4168c5 100644
--- a/gitg/gitg-runner.c
+++ b/gitg/gitg-runner.c
@@ -569,29 +569,41 @@ gitg_runner_run_streams (GitgRunner *runner,
 }
 
 gboolean
-gitg_runner_run_with_arguments(GitgRunner *runner, gchar const **argv, gchar const *wd, gchar const *input, GError **error)
+gitg_runner_run_with_arguments (GitgRunner *runner,
+                                GFile *work_tree,
+                                gchar const **argv,
+                                gchar const *input,
+                                GError **error)
 {
-	g_return_val_if_fail(GITG_IS_RUNNER(runner), FALSE);
+	g_return_val_if_fail (GITG_IS_RUNNER(runner), FALSE);
 
 	gint stdout;
 	gint stdin;
 
-	gitg_runner_cancel(runner);
+	gitg_runner_cancel (runner);
+	gchar *wd = NULL;
+
+	if (work_tree)
+	{
+		wd = g_file_get_path (work_tree);
+	}
 
-	gboolean ret = g_spawn_async_with_pipes(wd, 
-	                                        (gchar **)argv, 
-	                                        runner->priv->environment, 
-	                                        G_SPAWN_SEARCH_PATH | 
-	                                        G_SPAWN_DO_NOT_REAP_CHILD | 
-	                                        (gitg_debug_enabled(GITG_DEBUG_RUNNER) ? 0 : G_SPAWN_STDERR_TO_DEV_NULL), 
-	                                        NULL, 
-	                                        NULL,
-	                                         &(runner->priv->pid), 
-	                                         input ? &stdin : NULL, 
-	                                         &stdout, 
-	                                         NULL, 
+	gboolean ret = g_spawn_async_with_pipes (wd,
+	                                         (gchar **)argv,
+	                                         runner->priv->environment,
+	                                         G_SPAWN_SEARCH_PATH |
+	                                         G_SPAWN_DO_NOT_REAP_CHILD |
+	                                         (gitg_debug_enabled(GITG_DEBUG_RUNNER) ? 0 : G_SPAWN_STDERR_TO_DEV_NULL),
+	                                         NULL,
+	                                         NULL,
+	                                         &(runner->priv->pid),
+	                                         input ? &stdin : NULL,
+	                                         &stdout,
+	                                         NULL,
 	                                         error);
 
+	g_free (wd);
+
 	if (!ret)
 	{
 		runner->priv->pid = 0;
@@ -617,15 +629,11 @@ gitg_runner_run_with_arguments(GitgRunner *runner, gchar const **argv, gchar con
 }
 
 gboolean
-gitg_runner_run_working_directory(GitgRunner *runner, gchar const **argv, gchar const *wd, GError **error)
-{
-	return gitg_runner_run_with_arguments(runner, argv, wd, NULL, error);
-}
-
-gboolean
-gitg_runner_run(GitgRunner *runner, gchar const **argv, GError **error)
+gitg_runner_run (GitgRunner *runner,
+                 gchar const **argv,
+                 GError **error)
 {
-	return gitg_runner_run_working_directory(runner, argv, NULL, error);
+	return gitg_runner_run_with_arguments (runner, NULL, argv, NULL, error);
 }
 
 gboolean
diff --git a/gitg/gitg-runner.h b/gitg/gitg-runner.h
index 7c0944f..54a5c16 100644
--- a/gitg/gitg-runner.h
+++ b/gitg/gitg-runner.h
@@ -64,25 +64,34 @@ struct _GitgRunnerClass {
 };
 
 GType gitg_runner_get_type (void) G_GNUC_CONST;
-GitgRunner *gitg_runner_new(guint buffer_size);
-GitgRunner *gitg_runner_new_synchronized(guint buffer_size);
+GitgRunner *gitg_runner_new (guint buffer_size);
+GitgRunner *gitg_runner_new_synchronized (guint buffer_size);
 
-guint gitg_runner_get_buffer_size(GitgRunner *runner);
+guint gitg_runner_get_buffer_size (GitgRunner *runner);
 
-gboolean gitg_runner_run_stream(GitgRunner *runner, GInputStream *stream, GError **error);
+gboolean gitg_runner_run_stream (GitgRunner *runner,
+                                 GInputStream *stream,
+                                 GError **error);
 
-gboolean gitg_runner_run_with_arguments(GitgRunner *runner, gchar const **argv, gchar const *wd, gchar const *input, GError **error);
-gboolean gitg_runner_run_working_directory(GitgRunner *runner, gchar const **argv, gchar const *wd, GError **error);
-gboolean gitg_runner_run(GitgRunner *runner, gchar const **argv, GError **error);
-gboolean gitg_runner_running(GitgRunner *runner);
+gboolean gitg_runner_run_with_arguments (GitgRunner *runner,
+                                         GFile *work_tree,
+                                         gchar const **argv,
+                                         gchar const *input,
+                                         GError **error);
 
-gint gitg_runner_get_exit_status(GitgRunner *runner);
-void gitg_runner_cancel(GitgRunner *runner);
+gboolean gitg_runner_run (GitgRunner *runner,
+                          gchar const **argv,
+                          GError **error);
+
+gboolean gitg_runner_running (GitgRunner *runner);
+
+gint gitg_runner_get_exit_status (GitgRunner *runner);
+void gitg_runner_cancel (GitgRunner *runner);
 
 void gitg_runner_set_environment (GitgRunner *runner, gchar const **environment);
-void gitg_runner_add_environment(GitgRunner *runner, gchar const *key, gchar const *value);
+void gitg_runner_add_environment (GitgRunner *runner, gchar const *key, gchar const *value);
 
-GQuark gitg_runner_error_quark();
+GQuark gitg_runner_error_quark ();
 
 G_END_DECLS
 
diff --git a/gitg/gitg-utils.c b/gitg/gitg-utils.c
index 7d0cf27..c66c908 100644
--- a/gitg/gitg-utils.c
+++ b/gitg/gitg-utils.c
@@ -116,106 +116,96 @@ gitg_utils_sha1_to_hash_new(gchar const *sha1)
 	return ret;
 }
 
-static gchar *
-find_dot_git(gchar *path)
+GFile *
+gitg_utils_find_dot_git (GFile *location)
 {
-	while (strcmp(path, ".") != 0 && strcmp(path, "/") != 0)
-	{
-		gchar *res = g_build_filename(path, ".git", NULL);
+	location = g_file_dup (location);
 
-		if (g_file_test(res, G_FILE_TEST_IS_DIR))
-		{
-			g_free(res);
-			return path;
-		}
+	do
+	{
+		GFile *tmp;
+		gboolean exists;
 
-		gchar *tmp = g_path_get_dirname(path);
-		g_free(path);
-		path = tmp;
+		tmp = g_file_get_child (location, ".git");
+		exists = g_file_query_exists (tmp, NULL);
 
-		g_free(res);
-	}
-
-	return NULL;
-}
+		if (exists)
+		{
+			g_object_unref (location);
+			location = tmp;
 
-gchar *
-gitg_utils_find_git(gchar const *path)
-{
-	gchar const *find = G_DIR_SEPARATOR_S ".git";
-	gchar *dir;
+			break;
+		}
 
-	if (strstr(path, find) == path + strlen(path) - strlen(find))
-		dir = g_strndup(path, strlen(path) - strlen(find));
-	else
-		dir = g_strdup(path);
+		g_object_unref (tmp);
 
-	return find_dot_git(dir);
-}
+		tmp = g_file_get_parent (location);
 
-gchar *
-gitg_utils_dot_git_path(gchar const *path)
-{
-	gchar const *find = G_DIR_SEPARATOR_S ".git";
+		g_object_unref (location);
+		location = tmp;
+	} while (location != NULL);
 
-	if (strstr(path, find) == path + strlen(path) - strlen(find))
-		return g_strdup(path);
-	else
-		return g_build_filename(path, ".git", NULL);
+	return location;
 }
 
 static void
-append_escape(GString *gstr, gchar const *item)
+append_escape (GString *gstr, gchar const *item)
 {
-	gchar *escape = g_shell_quote(item);
+	gchar *escape = g_shell_quote (item);
 
-	g_string_append_printf(gstr, " %s", escape);
+	g_string_append_printf (gstr, " %s", escape);
+	g_free (escape);
 }
 
-gboolean 
-gitg_utils_export_files(GitgRepository *repository, GitgRevision *revision,
-gchar const *todir, gchar * const *paths)
+gboolean
+gitg_utils_export_files (GitgRepository *repository,
+                         GitgRevision *revision,
+                         gchar const *todir,
+                         gchar * const *paths)
 {
 	GString *gstr = g_string_new("sh -c \"git --git-dir");
 
-	// Append the git path
-	gchar *gitpath = gitg_utils_dot_git_path(gitg_repository_get_path(repository));
-	append_escape(gstr, gitpath);
-	g_free(gitpath);
+	GFile *git_dir = gitg_repository_get_git_dir (repository);
+	gchar *git_path = g_file_get_path (git_dir);
+
+	append_escape (gstr, git_path);
+
+	g_free (git_path);
+	g_object_unref (git_dir);
 
 	// Append the revision
-	gchar *sha = gitg_revision_get_sha1(revision);
-	g_string_append_printf(gstr, " archive --format=tar %s", sha);
+	gchar *sha = gitg_revision_get_sha1 (revision);
+	g_string_append_printf (gstr, " archive --format=tar %s", sha);
 	g_free(sha);
 
 	// Append the files
 	while (*paths)
 	{
-		append_escape(gstr, *paths);
+		append_escape (gstr, *paths);
 		paths++;
 	}
 
-	g_string_append(gstr, " | tar -xC");
-	append_escape(gstr, todir);
-	g_string_append(gstr, "\"");
+	g_string_append (gstr, " | tar -xC");
+	append_escape (gstr, todir);
+	g_string_append (gstr, "\"");
 
 	GError *error = NULL;
 	gint status;
 
-	gboolean ret = g_spawn_command_line_sync(gstr->str, NULL, NULL, &status, &error);
+	gboolean ret = g_spawn_command_line_sync (gstr->str, NULL, NULL, &status, &error);
 
 	if (!ret)
 	{
-		g_warning("Export failed:\n%s\n%s", gstr->str, error->message);
-		g_error_free(error);
+		g_warning ("Export failed:\n%s\n%s", gstr->str, error->message);
+		g_error_free (error);
 	}
 
-	g_string_free(gstr, TRUE);
+	g_string_free (gstr, TRUE);
 	return ret;
 }
 
-gchar *
-convert_fallback(gchar const *text, gssize size, gchar const *fallback)
+static gchar *
+convert_fallback (gchar const *text, gssize size, gchar const *fallback)
 {
 	gchar *res;
 	gsize read, written;
diff --git a/gitg/gitg-utils.h b/gitg/gitg-utils.h
index e5d8e27..1ae8d3c 100644
--- a/gitg/gitg-utils.h
+++ b/gitg/gitg-utils.h
@@ -40,8 +40,7 @@ gchar *gitg_utils_hash_to_sha1_new(gchar const *hash);
 
 gchar *gitg_utils_partial_sha1_to_hash_new (gchar const *sha, gint length, gint *retlen);
 
-gchar *gitg_utils_find_git(gchar const *path);
-gchar *gitg_utils_dot_git_path(gchar const *path);
+GFile *gitg_utils_find_dot_git (GFile *location);
 
 gboolean gitg_utils_export_files(GitgRepository *repository, GitgRevision *revision,
 gchar const *todir, gchar * const *paths);
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index ac3c0b0..fd2c400 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -887,21 +887,13 @@ on_repository_loaded (GitgRepository *repository, GitgWindow *window)
 }
 
 static void
-on_update(GitgRunner *loader, gchar **revisions, GitgWindow *window)
+on_update (GitgRunner *loader, gchar **revisions, GitgWindow *window)
 {
-	gchar *msg = g_strdup_printf(_("Loading %d revisions..."), gtk_tree_model_iter_n_children(GTK_TREE_MODEL(window->priv->repository), NULL));
+	gchar *msg = g_strdup_printf (_("Loading %d revisions..."),
+	                              gtk_tree_model_iter_n_children (GTK_TREE_MODEL(window->priv->repository), NULL));
 
-	gtk_statusbar_push(window->priv->statusbar, 0, msg);
-	g_free(msg);
-}
-
-static void
-handle_no_gitdir(GitgWindow *window)
-{
-	GtkWidget *dlg = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not find git repository"));
-
-	gtk_dialog_run(GTK_DIALOG(dlg));
-	gtk_widget_destroy(dlg);
+	gtk_statusbar_push (window->priv->statusbar, 0, msg);
+	g_free (msg);
 }
 
 void
@@ -924,83 +916,67 @@ gitg_window_set_select_on_load (GitgWindow  *window,
 }
 
 static gboolean
-create_repository(GitgWindow *window, gchar const *path, gboolean usewd)
+parse_gitg_uri (GFile *file, GFile **work_tree, gchar **selection)
 {
-	gboolean ret = TRUE;
-	gchar *selection = NULL;
-
-	if (path)
+	if (selection)
 	{
-		GFile *file = g_file_new_for_commandline_arg(path);
-
-		if (g_file_has_uri_scheme (file, "gitg"))
-		{
-			/* Extract path and sha information */
-			gchar *uri = g_file_get_uri (file);
-			gchar *fd = strrchr (uri, ':');
-			gint pos = fd ? fd - uri : 0;
-
-			if (pos > 5 && strlen (uri) - pos - 1 <= 40)
-			{
-				/* It has a sha */
-				*fd = '\0';
-				selection = g_strdup (fd + 1);
-			}
+		*selection = NULL;
+	}
 
-			g_object_unref (file);
+	if (work_tree)
+	{
+		*work_tree = NULL;
+	}
 
-			file = g_file_new_for_path (uri + 7);
-			g_free (uri);
-		}
+	if (!g_file_has_uri_scheme (file, "gitg"))
+	{
+		return FALSE;
+	}
 
-		if (g_file_is_native(file) && g_file_query_exists(file, NULL))
-		{
-			gchar *p = g_file_get_path(file);
-			window->priv->repository = gitg_repository_new(p);
-			g_free(p);
+	/* Extract path and sha information */
+	gchar *uri = g_file_get_uri (file);
+	gchar *fd = strrchr (uri, ':');
+	gint pos = fd ? fd - uri : 0;
 
-			if (!gitg_repository_get_path(window->priv->repository))
-			{
-				// Try current directory
-				path = NULL;
-				g_object_unref(window->priv->repository);
-				window->priv->repository = NULL;
+	if (pos > 5 && strlen (uri) - pos - 1 <= 40)
+	{
+		/* It has a sha */
+		*fd = '\0';
 
-				ret = FALSE;
-			}
-		}
-		else
+		if (selection)
 		{
-			ret = FALSE;
-			path = NULL;
+			*selection = g_strdup (fd + 1);
 		}
-
-		g_object_unref(file);
 	}
 
-	if (!path && usewd)
+	if (work_tree)
 	{
-		gchar *curdir = g_get_current_dir();
-		window->priv->repository = gitg_repository_new(curdir);
-		g_free(curdir);
+		*work_tree = g_file_new_for_path (uri + 7);
+	}
 
-		if (!gitg_repository_get_path (window->priv->repository))
-		{
-			g_object_unref (window->priv->repository);
-			window->priv->repository = NULL;
+	g_free (uri);
+	return TRUE;
+}
 
-			ret = FALSE;
-			path = NULL;
-		}
-	}
+static gboolean
+create_repository (GitgWindow  *window,
+                   GFile       *git_dir,
+                   GFile       *work_tree,
+                   gchar const *selection)
+{
+	window->priv->repository = gitg_repository_new (git_dir, work_tree);
 
-	if (ret && selection)
+	if (!gitg_repository_exists (window->priv->repository))
+	{
+		g_object_unref (window->priv->repository);
+		window->priv->repository = NULL;
+	}
+	else if (selection)
 	{
 		gitg_window_set_select_on_load (window, selection);
-		g_free (selection);
 	}
 
-	return ret;
+	return window->priv->repository != NULL;
 }
 
 static int
@@ -1280,13 +1256,15 @@ update_window_title (GitgWindow *window)
 		refname = g_strconcat (" (", gitg_ref_get_shortname (ref), ")", NULL);
 	}
 
-	gchar *basename = g_path_get_basename(gitg_repository_get_path(window->priv->repository));
-	gchar *title = g_strconcat(_("gitg"), " - ", basename, refname, NULL);
+	GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository);
+	gchar *basename = g_file_get_basename (work_tree);
+	gchar *title = g_strconcat (_("gitg"), " - ", basename, refname, NULL);
 
-	gtk_window_set_title(GTK_WINDOW(window), title);
+	gtk_window_set_title (GTK_WINDOW (window), title);
 
-	g_free(basename);
-	g_free(title);
+	g_object_unref (work_tree);
+	g_free (basename);
+	g_free (title);
 	g_free (refname);
 }
 
@@ -1317,13 +1295,13 @@ on_repository_load (GitgRepository *repository, GitgWindow *window)
 }
 
 static void
-add_recent_item(GitgWindow *window)
+add_recent_item (GitgWindow *window)
 {
-	GtkRecentManager *manager = gtk_recent_manager_get_default();
+	GtkRecentManager *manager = gtk_recent_manager_get_default ();
 	GtkRecentData data = { 0 };
 	gchar *groups[] = {"gitg", NULL};
-	gchar const *path = gitg_repository_get_path(window->priv->repository);
-	gchar *basename = g_path_get_basename(path);
+	GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository);
+	gchar *basename = g_file_get_basename (work_tree);
 
 	data.display_name = basename;
 	data.app_name = "gitg";
@@ -1331,17 +1309,21 @@ add_recent_item(GitgWindow *window)
 	data.app_exec = "gitg %f";
 	data.groups = groups;
 
-	GFile *file = g_file_new_for_path(gitg_repository_get_path(window->priv->repository));
-	gchar *uri = g_file_get_uri(file);
-	gtk_recent_manager_add_full(manager, uri, &data);
+	gchar *uri = g_file_get_uri (work_tree);
+	gtk_recent_manager_add_full (manager, uri, &data);
 
-	g_free(basename);
-	g_free(uri);
-	g_object_unref(file);
+	g_free (basename);
+	g_free (uri);
+	g_object_unref (work_tree);
 }
 
-static void
-load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **argv, gboolean usewd, gchar const *selection)
+static gboolean
+load_repository (GitgWindow *window,
+                 GFile *git_dir,
+                 GFile *work_tree,
+                 gint argc,
+                 gchar const **argv,
+                 gchar const *selection)
 {
 	if (window->priv->repository)
 	{
@@ -1363,31 +1345,17 @@ load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **
 		memset (window->priv->select_on_load, 0, HASH_BINARY_SIZE);
 	}
 
-	gboolean haspath = create_repository(window, path, usewd);
-
-	if (window->priv->repository && gitg_repository_get_path(window->priv->repository))
+	if (create_repository (window, git_dir, work_tree, selection))
 	{
-		gtk_tree_view_set_model(window->priv->tree_view, GTK_TREE_MODEL(window->priv->repository));
-		GitgRunner *loader = gitg_repository_get_loader(window->priv->repository);
-
-		gitg_window_set_select_on_load (window, selection);
-
-		g_signal_connect(loader, "update", G_CALLBACK(on_update), window);
-
-		g_object_unref(loader);
+		gtk_tree_view_set_model (window->priv->tree_view,
+		                         GTK_TREE_MODEL (window->priv->repository));
 
-		gchar const **ar = argv;
+		GitgRunner *loader = gitg_repository_get_loader (window->priv->repository);
 
-		if (!haspath && path)
-		{
-			ar = (gchar const **)g_new(gchar *, ++argc);
-
-			int i;
-			for (i = 0; i < argc - 1; ++i)
-				ar[i] = argv[i];
+		gitg_window_set_select_on_load (window, selection);
 
-			ar[argc - 1] = path;
-		}
+		g_signal_connect (loader, "update", G_CALLBACK (on_update), window);
+		g_object_unref (loader);
 
 		g_signal_connect (window->priv->repository,
 		                  "load",
@@ -1399,43 +1367,171 @@ load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **
 		                  G_CALLBACK (on_repository_loaded),
 		                  window);
 
-		clear_branches_combo(window);
+		clear_branches_combo (window);
 
-		gitg_repository_load(window->priv->repository, argc, ar, NULL);
+		gitg_repository_load (window->priv->repository, argc, argv, NULL);
+
+		gitg_commit_view_set_repository (window->priv->commit_view,
+		                                 window->priv->repository);
+
+		gitg_revision_view_set_repository (window->priv->revision_view,
+		                                  window->priv->repository);
+
+		add_recent_item (window);
+		gtk_widget_set_sensitive (GTK_WIDGET (window->priv->notebook_main), TRUE);
+	}
+	else
+	{
+		clear_branches_combo (window);
+
+		gitg_commit_view_set_repository (window->priv->commit_view,
+		                                 NULL);
+
+		gitg_revision_view_set_repository (window->priv->revision_view,
+		                                   NULL);
+
+		update_window_title (window);
+		gtk_widget_set_sensitive (GTK_WIDGET (window->priv->notebook_main), FALSE);
+	}
 
-		if (!haspath && path)
+	return window->priv->repository != NULL;
+}
+
+gboolean
+gitg_window_load_repository (GitgWindow *window,
+                             GFile *git_dir,
+                             GFile *work_tree,
+                             gint argc,
+                             gchar const **argv,
+                             gchar const *selection)
+{
+	g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE);
+
+	return load_repository (window,
+	                        git_dir,
+	                        work_tree,
+	                        argc,
+	                        argv,
+	                        selection);
+}
+
+static gboolean
+load_repository_for_command_line (GitgWindow *window,
+                                  gint argc,
+                                  gchar const **argv,
+                                  gchar const *selection)
+{
+	gboolean ret = FALSE;
+	GFile *git_dir = NULL;
+	GFile *work_tree = NULL;
+
+	if (argc > 0)
+	{
+		GFile *first_arg = g_file_new_for_commandline_arg (argv[0]);
+		gchar *sel;
+
+		if (!parse_gitg_uri (first_arg, &work_tree, &sel))
 		{
-			g_free(ar);
+			git_dir = gitg_utils_find_dot_git (first_arg);
 		}
 
-		gitg_commit_view_set_repository(window->priv->commit_view, window->priv->repository);
-		gitg_revision_view_set_repository(window->priv->revision_view, window->priv->repository);
+		if (git_dir || (work_tree && g_file_query_exists (work_tree, NULL)))
+		{
+			ret = load_repository (window,
+			                       git_dir,
+			                       work_tree,
+			                       argc - 1,
+			                       argv + 1,
+			                       selection ? selection : sel);
+		}
 
-		add_recent_item(window);
-		gtk_widget_set_sensitive(GTK_WIDGET(window->priv->notebook_main), TRUE);
+		g_free (sel);
+		g_object_unref (first_arg);
 	}
-	else
+
+	if (!ret)
 	{
-		clear_branches_combo(window);
-		gitg_commit_view_set_repository(window->priv->commit_view, window->priv->repository);
-		gitg_revision_view_set_repository(window->priv->revision_view, window->priv->repository);
+		gchar *cwd = g_get_current_dir ();
+
+		GFile *file = g_file_new_for_path (cwd);
+		git_dir = gitg_utils_find_dot_git (file);
 
-		if (path || argc > 1)
+		g_free (cwd);
+		g_object_unref (file);
+
+		if (git_dir)
 		{
-			handle_no_gitdir(window);
+			ret = load_repository (window,
+			                       git_dir,
+			                       NULL,
+			                       argc,
+			                       argv,
+			                       selection);
 		}
+	}
 
-		update_window_title (window);
-		gtk_widget_set_sensitive(GTK_WIDGET(window->priv->notebook_main), FALSE);
+	if (git_dir)
+	{
+		g_object_unref (git_dir);
 	}
+
+	if (work_tree)
+	{
+		g_object_unref (work_tree);
+	}
+
+	return ret;
 }
 
-void
-gitg_window_load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **argv, gchar const *selection)
+gboolean
+gitg_window_load_repository_for_command_line (GitgWindow *window,
+                                              gint argc,
+                                              gchar const **argv,
+                                              gchar const *selection)
 {
-	g_return_if_fail(GITG_IS_WINDOW(window));
+	gboolean ret;
 
-	load_repository(window, path, argc, argv, TRUE, selection);
+	g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE);
+
+	gchar const *git_dir_path = g_getenv ("GIT_DIR");
+	gchar const *work_tree_path = g_getenv ("GIT_WORK_TREE");
+
+	if (!git_dir_path && !work_tree_path)
+	{
+		return load_repository_for_command_line (window, argc, argv, selection);
+	}
+
+	GFile *git_dir = NULL;
+	GFile *work_tree = NULL;
+
+	if (git_dir_path)
+	{
+		git_dir = g_file_new_for_commandline_arg (git_dir_path);
+	}
+
+	if (work_tree_path)
+	{
+		work_tree = g_file_new_for_commandline_arg (work_tree_path);
+	}
+
+	ret = gitg_window_load_repository (window,
+	                                   git_dir,
+	                                   work_tree,
+	                                   argc,
+	                                   argv,
+	                                   selection);
+
+	if (git_dir)
+	{
+		g_object_unref (git_dir);
+	}
+
+	if (work_tree)
+	{
+		g_object_unref (work_tree);
+	}
+
+	return ret;
 }
 
 void
@@ -1472,16 +1568,11 @@ on_open_dialog_response (GtkFileChooser *dialog,
 		return;
 	}
 
-	gchar *uri = gtk_file_chooser_get_uri(dialog);
-	GFile *file = g_file_new_for_uri(uri);
-	gchar *path = g_file_get_path(file);
+	GFile *file = gtk_file_chooser_get_file (dialog);
+	gtk_widget_destroy (GTK_WIDGET(dialog));
 
-	g_free(uri);
-	g_object_unref(file);
-	gtk_widget_destroy(GTK_WIDGET(dialog));
-
-	load_repository(window, path, 0, NULL, FALSE, NULL);
-	g_free(path);
+	load_repository (window, NULL, file, 0, NULL, NULL);
+	g_object_unref (file);
 }
 
 void
@@ -1534,11 +1625,12 @@ on_edit_paste (GtkAction *action, GitgWindow *window)
 }
 
 void
-on_view_refresh(GtkAction *action, GitgWindow *window)
+on_view_refresh (GtkAction *action, GitgWindow *window)
 {
-	if (window->priv->repository && gitg_repository_get_path(window->priv->repository) != NULL)
+	if (window->priv->repository &&
+	    gitg_repository_exists (window->priv->repository))
 	{
-		gitg_repository_reload(window->priv->repository);
+		gitg_repository_reload (window->priv->repository);
 	}
 }
 
@@ -1564,33 +1656,22 @@ on_window_set_focus (GitgWindow *window, GtkWidget *widget)
 	gtk_action_set_sensitive(gtk_action_group_get_action(window->priv->edit_group, "EditCopyAction"), cancopy);
 }
 
-gboolean
-on_window_state_event(GtkWidget *widget, GdkEventWindowState *event, GitgWindow *window)
-{
-	GitgSettings *settings = gitg_settings_get_default();
-
-	gitg_settings_set_window_state(settings, event->new_window_state);
-
-	return FALSE;
-}
-
 void
-on_recent_open(GtkRecentChooser *chooser, GitgWindow *window)
+on_recent_open (GtkRecentChooser *chooser, GitgWindow *window)
 {
-	GFile *file = g_file_new_for_uri(gtk_recent_chooser_get_current_uri(chooser));
-	gchar *path = g_file_get_path(file);
+	gchar *uri = gtk_recent_chooser_get_current_uri (chooser);
+	GFile *work_tree = g_file_new_for_uri (uri);
+	g_free (uri);
 
-	load_repository(window, path, 0, NULL, FALSE, NULL);
+	load_repository (window, NULL, work_tree, 0, NULL, NULL);
 
-	g_free(path);
-	g_object_unref(file);
+	g_object_unref (work_tree);
 }
 
-#if GTK_CHECK_VERSION (2, 14, 0)
 static void
-url_activate_hook(GtkAboutDialog *dialog, gchar const *link, gpointer data)
+url_activate_hook (GtkAboutDialog *dialog, gchar const *link, gpointer data)
 {
-	gtk_show_uri(NULL, link, GDK_CURRENT_TIME, NULL);
+	gtk_show_uri (NULL, link, GDK_CURRENT_TIME, NULL);
 }
 
 static void
@@ -1599,18 +1680,17 @@ email_activate_hook (GtkAboutDialog *dialog, gchar const *link, gpointer data)
 	gchar *uri;
 	gchar *escaped;
 
-	escaped = g_uri_escape_string(link, NULL, FALSE);
-	uri = g_strdup_printf("mailto:%s";, escaped);
+	escaped = g_uri_escape_string (link, NULL, FALSE);
+	uri = g_strdup_printf ("mailto:%s";, escaped);
 
-	gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, NULL);
+	gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL);
 
-	g_free(uri);
-	g_free(escaped);
+	g_free (uri);
+	g_free (escaped);
 }
-#endif
 
 void
-on_help_about(GtkAction *action, GitgWindow *window)
+on_help_about (GtkAction *action, GitgWindow *window)
 {
 	static gchar const copyright[] = "Copyright \xc2\xa9 2009 Jesse van den Kieboom";
 	static gchar const *authors[] = {"Jesse van den Kieboom <jessevdk gnome org>", NULL};
@@ -2655,8 +2735,13 @@ on_revision_format_patch_activate (GtkAction *action, GitgWindow *window)
 		/* TODO: Implement selecting folder once multiple selection is realized */
 	}
 
-	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
-	                                     gitg_repository_get_path (window->priv->repository));
+	GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository);
+
+	gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog),
+	                                          work_tree,
+	                                          NULL);
+
+	g_object_unref (work_tree);
 
 	FormatPatchInfo *info = g_slice_new (FormatPatchInfo);
 	info->window = window;
diff --git a/gitg/gitg-window.h b/gitg/gitg-window.h
index 1d2b988..d7d0ffc 100644
--- a/gitg/gitg-window.h
+++ b/gitg/gitg-window.h
@@ -52,8 +52,24 @@ struct _GitgWindowClass {
 
 GType gitg_window_get_type (void) G_GNUC_CONST;
 
-void gitg_window_load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **argv, gchar const *selection);
-void gitg_window_show_commit(GitgWindow *window);
+gboolean gitg_window_load_repository (GitgWindow *window,
+                                      GFile *git_dir,
+                                      GFile *work_tree,
+                                      gint argc,
+                                      gchar const **argv,
+                                      gchar const *selection);
+
+gboolean gitg_window_load_repository_for_command_line (GitgWindow *window,
+                                                       gint argc,
+                                                       gchar const **argv,
+                                                       gchar const *selection);
+
+gboolean gitg_window_load_repository_from_environment (GitgWindow *window,
+                                                       gint argc,
+                                                       gchar const **argv,
+                                                       gchar const *selection);
+
+void gitg_window_show_commit (GitgWindow *window);
 
 GitgRepository *gitg_window_get_repository(GitgWindow *window);
 void gitg_window_set_select_on_load (GitgWindow *window, gchar const *selection);
diff --git a/gitg/gitg.c b/gitg/gitg.c
index 7060603..21d8aea 100644
--- a/gitg/gitg.c
+++ b/gitg/gitg.c
@@ -167,41 +167,47 @@ set_icons ()
 }
 
 int
-main(int argc, char **argv)
+main (int argc, char **argv)
 {
-	g_thread_init(NULL);
+	gboolean ret;
 
-	gitg_debug_init();
+	g_thread_init (NULL);
 
-	bindtextdomain(GETTEXT_PACKAGE, GITG_LOCALEDIR);
-	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
-	textdomain(GETTEXT_PACKAGE);
+	gitg_debug_init ();
 
-	g_set_prgname("gitg");
+	bindtextdomain (GETTEXT_PACKAGE, GITG_LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
 
-	/* Translators: this is the application name as in g_set_application_name */
-	g_set_application_name(_("gitg"));
+	g_set_prgname ("gitg");
 
-	gitg_dirs_initialize(argc, argv);
-	gtk_init(&argc, &argv);
-	parse_options(&argc, &argv);
+	/* Translators: this is the application name as in g_set_application_name */
+	g_set_application_name (_("gitg"));
 
-	set_language_search_path();
-	set_style_scheme_search_path();
-	set_icons();
+	gitg_dirs_initialize (argc, argv);
+	gtk_init (&argc, &argv);
+	parse_options (&argc, &argv);
 
-	GitgSettings *settings = gitg_settings_get_default();
+	set_language_search_path ();
+	set_style_scheme_search_path ();
+	set_icons ();
 
-	GitgWindow *window = build_ui();
+	GitgSettings *settings = gitg_settings_get_default ();
+	GitgWindow *window = build_ui ();
 
-	gitg_window_load_repository(window, argc > 1 ? argv[1] : NULL, argc - 2, argc > 1 ? (gchar const **)&argv[2] : NULL, select_sha1);
+	ret = gitg_window_load_repository_for_command_line (window,
+	                                                    argc - 1,
+	                                                    (gchar const **)argv + 1,
+	                                                    select_sha1);
 
-	if (commit_mode && gitg_window_get_repository (window) != NULL)
-		gitg_window_show_commit(window);
+	if (commit_mode && ret)
+	{
+		gitg_window_show_commit (window);
+	}
 
-	gtk_main();
+	gtk_main ();
 
 	/* Finalize settings */
-	g_object_unref(settings);
+	g_object_unref (settings);
 	return 0;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]