[gitg] Implemented cherry-picking



commit 684f9172e90670683b12dc0c64ffb7c1e5086132
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Sat Jan 9 22:18:28 2010 +0100

    Implemented cherry-picking

 gitg/gitg-branch-actions.c |  182 ++++++++++++++++++++++++++++++++++++++++++++
 gitg/gitg-branch-actions.h |    2 +
 gitg/gitg-dnd.c            |   26 +++++--
 gitg/gitg-dnd.h            |    8 ++-
 gitg/gitg-window.c         |   43 ++++++++++-
 5 files changed, 253 insertions(+), 8 deletions(-)
---
diff --git a/gitg/gitg-branch-actions.c b/gitg/gitg-branch-actions.c
index 7f83bee..68f9a17 100644
--- a/gitg/gitg-branch-actions.c
+++ b/gitg/gitg-branch-actions.c
@@ -1594,3 +1594,185 @@ gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *nam
 		return TRUE;
 	}
 }
+
+typedef struct
+{
+	GitgRevision *revision;
+	GitgRef *dest;
+
+	gchar *stashcommit;
+	GitgRef *head;
+} CherryPickInfo;
+
+static CherryPickInfo *
+cherry_pick_info_new (GitgRevision *revision, GitgRef *dest)
+{
+	CherryPickInfo *ret = g_slice_new0 (CherryPickInfo);
+
+	ret->revision = gitg_revision_ref (revision);
+	ret->dest = gitg_ref_copy (dest);
+
+	return ret;
+}
+
+static void
+cherry_pick_info_free (CherryPickInfo *info)
+{
+	gitg_revision_unref (info->revision);
+	gitg_ref_free (info->dest);
+
+	g_free (info->stashcommit);
+	gitg_ref_free (info->head);
+
+	g_slice_free (CherryPickInfo, info);
+}
+
+static void
+on_cherry_pick_result (GitgWindow   *window,
+                       GitgProgress  progress,
+                       gpointer      data)
+{
+	CherryPickInfo *info = (CherryPickInfo *)data;
+
+	if (progress == GITG_PROGRESS_ERROR)
+	{
+		gchar const *message;
+
+		message_dialog (window,
+			            GTK_MESSAGE_ERROR,
+			            _("Failed to cherry-pick on <%s>"),
+			            NULL,
+			            NULL,
+	                    gitg_ref_get_shortname (info->dest));
+	}
+	else if (progress == GITG_PROGRESS_SUCCESS)
+	{
+		GitgRepository *repository = gitg_window_get_repository (window);
+
+		// Checkout head
+		if (!checkout_local_branch_real (window, info->head))
+		{
+			gchar const *message = NULL;
+
+			if (info->stashcommit)
+			{
+				gitg_repository_commandv (repository, NULL, 
+				                          "update-ref", "-m", "gitg autosave stash",
+				                          "refs/stash", info->stashcommit, NULL);
+				                          
+				message = _("The stashed changes have been stored to be reapplied manually");
+			}
+
+			message_dialog (window,
+				            GTK_MESSAGE_ERROR,
+				            _("Failed to checkout previously checked out branch"),
+				            message,
+				            NULL);
+		}
+		else if (info->stashcommit)
+		{
+			// Reapply stash
+			if (!gitg_repository_commandv (gitg_window_get_repository (window),
+			                               NULL,
+			                               "stash",
+			                               "apply",
+			                               "--index",
+			                               info->stashcommit,
+			                               NULL))
+			{
+				gitg_repository_commandv (repository, NULL, 
+				                          "update-ref", "-m", "gitg autosave stash",
+				                          "refs/stash", info->stashcommit, NULL);
+
+				message_dialog (window,
+				                GTK_MESSAGE_ERROR,
+				                _("Failed to reapply stash correctly"),
+				                _("There might be unresolved conflicts in the working tree or index which you need to resolve manually"),
+				                NULL);
+			}
+		}
+
+		gitg_repository_reload (gitg_window_get_repository (window));
+	}
+
+	cherry_pick_info_free (info);
+}
+
+GitgRunner *
+gitg_branch_actions_cherry_pick (GitgWindow   *window,
+                                 GitgRevision *revision,
+                                 GitgRef      *dest)
+{
+	g_return_val_if_fail (GITG_IS_WINDOW (window), NULL);
+	g_return_val_if_fail (revision != NULL, NULL);
+	g_return_val_if_fail (dest != NULL, NULL);
+
+	gchar *message = g_strdup_printf (_("Are you sure you want to cherry-pick that revision on <%s>?"),
+	                                  gitg_ref_get_shortname (dest));
+
+	if (message_dialog (window,
+	                    GTK_MESSAGE_QUESTION,
+	                    _("Cherry-pick"),
+	                    message,
+	                    _("Cherry-pick")) != GTK_RESPONSE_ACCEPT)
+	{
+		g_free (message);
+		return NULL;
+	}
+
+	gchar *stashcommit;
+
+	if (!stash_changes (window, &stashcommit, FALSE))
+	{
+		return NULL;
+	}
+
+	GitgRepository *repository = gitg_window_get_repository (window);
+	GitgRef *head = gitg_repository_get_current_working_ref (repository);
+
+	// First checkout the correct branch on which to cherry-pick
+	if (!gitg_repository_commandv (repository,
+	                               NULL,
+	                               "checkout",
+	                               gitg_ref_get_shortname (dest),
+	                               NULL))
+	{
+		g_free (stashcommit);
+
+		message_dialog (window,
+		                GTK_MESSAGE_ERROR,
+		                _("Failed to checkout local branch <%s>"),
+		                _("The branch on which to cherry-pick could not be checked out"),
+		                NULL,
+		                gitg_ref_get_shortname (dest));
+
+		return NULL;
+	}
+
+	message = g_strdup_printf (_("Cherry-picking on <%s>"),
+	                           gitg_ref_get_shortname (dest));
+
+	GitgRunner *ret;
+
+	CherryPickInfo *info = cherry_pick_info_new (revision, dest);
+
+	info->stashcommit = stashcommit;
+	info->head = gitg_ref_copy (head);
+
+	gchar *sha1 = gitg_revision_get_sha1 (revision);
+
+	ret = run_progress (window,
+	                    _("Cherry-pick"),
+	                    message,
+	                    on_cherry_pick_result,
+	                    info,
+	                    "cherry-pick",
+	                    sha1,
+	                    NULL);
+
+	g_free (message);
+	gitg_ref_free (head);
+	g_free (sha1);
+
+	return ret;
+}
diff --git a/gitg/gitg-branch-actions.h b/gitg/gitg-branch-actions.h
index 80ab57d..b7b5859 100644
--- a/gitg/gitg-branch-actions.h
+++ b/gitg/gitg-branch-actions.h
@@ -42,6 +42,8 @@ gboolean gitg_branch_actions_apply_stash (GitgWindow *window, GitgRef *stash, Gi
 
 gboolean gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *name, gchar const *message, gboolean sign);
 
+GitgRunner *gitg_branch_actions_cherry_pick (GitgWindow *window, GitgRevision *revision, GitgRef *dest);
+
 G_END_DECLS
 
 #endif /* __GITG_BRANCH_ACTIONS_H__ */
diff --git a/gitg/gitg-dnd.c b/gitg/gitg-dnd.c
index 72152a1..949f096 100644
--- a/gitg/gitg-dnd.c
+++ b/gitg/gitg-dnd.c
@@ -29,6 +29,7 @@ typedef struct
 	GitgRef *cursor_ref;
 
 	GitgDndCallback callback;
+	GitgDndRevisionCallback revision_callback;
 	gpointer callback_data;
 
 	gdouble x;
@@ -554,7 +555,7 @@ gitg_drag_source_motion_cb (GtkWidget       *widget,
                             guint            time,
                             GitgDndData     *data)
 {
-	if (!data->ref)
+	if (!data->ref && !data->revision)
 	{
 		return FALSE;
 	}
@@ -587,13 +588,18 @@ gitg_drag_source_motion_cb (GtkWidget       *widget,
 			gtk_widget_queue_draw (widget);
 		}
 
-		if (data->callback)
+		if (data->ref && data->callback)
 		{
 			data->callback (data->ref, ref, FALSE, data->callback_data);
 		}
+		else if (data->revision && data->revision_callback)
+		{
+			data->revision_callback (data->revision, ref, FALSE, data->callback_data);
+		}
 	}
 
-	if (ref && can_drop (data->ref, ref))
+	if ((data->ref && ref && can_drop (data->ref, ref)) ||
+	    (data->revision && ref && gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH))
 	{
 		if (ref != data->target)
 		{
@@ -627,17 +633,21 @@ gitg_drag_source_drop_cb (GtkWidget *widget,
                           guint time,
                           GitgDndData *data)
 {
-	if (!data->ref || !data->target)
+	if (!(data->ref || data->revision) || !data->target)
 	{
 		return FALSE;
 	}
 
 	gboolean ret = FALSE;
 
-	if (data->callback)
+	if (data->ref && data->callback)
 	{
 		ret = data->callback (data->ref, data->target, TRUE, data->callback_data);
 	}
+	else if (data->revision && data->revision_callback)
+	{
+		ret = data->revision_callback (data->revision, data->target, TRUE, data->callback_data);
+	}
 
 	gtk_drag_finish (context, ret, FALSE, time);
 	return ret;
@@ -784,7 +794,10 @@ gitg_drag_source_data_get_cb (GtkWidget        *widget,
 }
 
 void
-gitg_dnd_enable (GtkTreeView *tree_view, GitgDndCallback callback, gpointer callback_data)
+gitg_dnd_enable (GtkTreeView             *tree_view,
+                 GitgDndCallback          callback,
+                 GitgDndRevisionCallback  revision_callback,
+                 gpointer                 callback_data)
 {
 	if (GITG_DND_GET_DATA (tree_view))
 	{
@@ -795,6 +808,7 @@ gitg_dnd_enable (GtkTreeView *tree_view, GitgDndCallback callback, gpointer call
 
 	data->tree_view = tree_view;
 	data->callback = callback;
+	data->revision_callback = revision_callback;
 	data->callback_data = callback_data;
 
 	g_object_set_data_full (G_OBJECT (tree_view),
diff --git a/gitg/gitg-dnd.h b/gitg/gitg-dnd.h
index 37a211b..cfce9f7 100644
--- a/gitg/gitg-dnd.h
+++ b/gitg/gitg-dnd.h
@@ -3,12 +3,18 @@
 
 #include <gtk/gtk.h>
 #include "gitg-ref.h"
+#include "gitg-revision.h"
 
 G_BEGIN_DECLS
 
 typedef gboolean (*GitgDndCallback)(GitgRef *source, GitgRef *dest, gboolean dropped, gpointer callback_data);
+typedef gboolean (*GitgDndRevisionCallback)(GitgRevision *source, GitgRef *dest, gboolean dropped, gpointer callback_data);
+
+void gitg_dnd_enable (GtkTreeView *tree_view,
+                      GitgDndCallback callback,
+                      GitgDndRevisionCallback revision_callback,
+                      gpointer callback_data);
 
-void gitg_dnd_enable (GtkTreeView *tree_view, GitgDndCallback callback, gpointer callback_data);
 void gitg_dnd_disable (GtkTreeView *tree_view);
 
 G_END_DECLS
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index 822ff94..6583758 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -581,6 +581,44 @@ on_refs_dnd (GitgRef *source, GitgRef *dest, gboolean dropped, GitgWindow *windo
 }
 
 static void
+update_revision_dnd_status (GitgWindow *window, GitgRevision *source, GitgRef *dest)
+{
+	if (!dest)
+	{
+		gtk_statusbar_push (window->priv->statusbar, 0, "");
+	}
+	else
+	{
+		gchar *message = g_strdup_printf (_("Cherry-pick revision on <%s>"),
+		                                  gitg_ref_get_shortname (dest));
+
+		gtk_statusbar_push (window->priv->statusbar, 0, message);
+		g_free (message);
+	}
+}
+
+static gboolean
+on_revision_dnd (GitgRevision *source,
+                 GitgRef      *dest,
+                 gboolean      dropped,
+                 GitgWindow   *window)
+{
+	if (!dropped)
+	{
+		update_revision_dnd_status (window, source, dest);
+		return FALSE;
+	}
+
+	if (gitg_ref_get_ref_type (dest) != GITG_REF_TYPE_BRANCH)
+	{
+		return FALSE;
+	}
+
+	return add_branch_action (window,
+	                          gitg_branch_actions_cherry_pick (window, source, dest));
+}
+
+static void
 init_tree_view (GitgWindow *window, GtkBuilder *builder)
 {
 	GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "rv_column_subject"));
@@ -589,7 +627,10 @@ init_tree_view (GitgWindow *window, GtkBuilder *builder)
 
 	gtk_tree_view_column_set_cell_data_func(col, GTK_CELL_RENDERER(window->priv->renderer_path), (GtkTreeCellDataFunc)on_renderer_path, window, NULL);
 
-	gitg_dnd_enable (window->priv->tree_view, (GitgDndCallback)on_refs_dnd, window);
+	gitg_dnd_enable (window->priv->tree_view,
+	                 (GitgDndCallback)on_refs_dnd,
+	                 (GitgDndRevisionCallback)on_revision_dnd,
+	                 window);
 }
 
 static void



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