Implemented cherry-picking

This commit is contained in:
Jesse van den Kieboom 2010-01-09 22:18:28 +01:00
parent 9c44c7e608
commit 684f9172e9
5 changed files with 253 additions and 8 deletions

View file

@ -1594,3 +1594,185 @@ gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *nam
return TRUE; 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;
}

View file

@ -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); 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 G_END_DECLS
#endif /* __GITG_BRANCH_ACTIONS_H__ */ #endif /* __GITG_BRANCH_ACTIONS_H__ */

View file

@ -29,6 +29,7 @@ typedef struct
GitgRef *cursor_ref; GitgRef *cursor_ref;
GitgDndCallback callback; GitgDndCallback callback;
GitgDndRevisionCallback revision_callback;
gpointer callback_data; gpointer callback_data;
gdouble x; gdouble x;
@ -554,7 +555,7 @@ gitg_drag_source_motion_cb (GtkWidget *widget,
guint time, guint time,
GitgDndData *data) GitgDndData *data)
{ {
if (!data->ref) if (!data->ref && !data->revision)
{ {
return FALSE; return FALSE;
} }
@ -587,13 +588,18 @@ gitg_drag_source_motion_cb (GtkWidget *widget,
gtk_widget_queue_draw (widget); gtk_widget_queue_draw (widget);
} }
if (data->callback) if (data->ref && data->callback)
{ {
data->callback (data->ref, ref, FALSE, data->callback_data); 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) if (ref != data->target)
{ {
@ -627,17 +633,21 @@ gitg_drag_source_drop_cb (GtkWidget *widget,
guint time, guint time,
GitgDndData *data) GitgDndData *data)
{ {
if (!data->ref || !data->target) if (!(data->ref || data->revision) || !data->target)
{ {
return FALSE; return FALSE;
} }
gboolean ret = FALSE; gboolean ret = FALSE;
if (data->callback) if (data->ref && data->callback)
{ {
ret = data->callback (data->ref, data->target, TRUE, data->callback_data); 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); gtk_drag_finish (context, ret, FALSE, time);
return ret; return ret;
@ -784,7 +794,10 @@ gitg_drag_source_data_get_cb (GtkWidget *widget,
} }
void 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)) 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->tree_view = tree_view;
data->callback = callback; data->callback = callback;
data->revision_callback = revision_callback;
data->callback_data = callback_data; data->callback_data = callback_data;
g_object_set_data_full (G_OBJECT (tree_view), g_object_set_data_full (G_OBJECT (tree_view),

View file

@ -3,12 +3,18 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "gitg-ref.h" #include "gitg-ref.h"
#include "gitg-revision.h"
G_BEGIN_DECLS G_BEGIN_DECLS
typedef gboolean (*GitgDndCallback)(GitgRef *source, GitgRef *dest, gboolean dropped, gpointer callback_data); 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); void gitg_dnd_disable (GtkTreeView *tree_view);
G_END_DECLS G_END_DECLS

View file

@ -580,6 +580,44 @@ on_refs_dnd (GitgRef *source, GitgRef *dest, gboolean dropped, GitgWindow *windo
return ret; return ret;
} }
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 static void
init_tree_view (GitgWindow *window, GtkBuilder *builder) init_tree_view (GitgWindow *window, GtkBuilder *builder)
{ {
@ -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); 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 static void