mirror of
https://gitlab.gnome.org/GNOME/gitg
synced 2024-10-31 04:58:58 +00:00
Implemented cherry-picking
This commit is contained in:
parent
9c44c7e608
commit
684f9172e9
5 changed files with 253 additions and 8 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue