Implemented stash actions (remove, apply)

This commit is contained in:
Jesse van den Kieboom 2009-07-05 16:53:43 +02:00
parent c9815fb2aa
commit 72bc8371af
9 changed files with 455 additions and 144 deletions

View file

@ -342,6 +342,109 @@ remove_remote_branch (GitgWindow *window,
return ret;
}
static gchar *
get_stash_refspec (GitgRepository *repository, GitgRef *stash)
{
gchar **out;
out = gitg_repository_command_with_outputv (repository,
NULL,
"log",
"--no-color",
"--pretty=oneline",
"-g",
"refs/stash",
NULL);
gchar **ptr = out;
gchar *sha1 = gitg_utils_hash_to_sha1_new (gitg_ref_get_hash (stash));
gchar *ret = NULL;
while (ptr && *ptr)
{
if (g_str_has_prefix (*ptr, sha1))
{
gchar *start = *ptr + HASH_SHA_SIZE + 1;
gchar *end = strchr (start, ':');
if (end)
{
ret = g_strndup (start, end - start);
}
break;
}
}
g_strfreev (out);
g_free (sha1);
return ret;
}
static GitgRunner *
remove_stash (GitgWindow *window, GitgRef *ref)
{
gint r = message_dialog (window,
GTK_MESSAGE_QUESTION,
_("Are you sure you want to remove this stash item?"),
_("This permanently removes the stash item"),
_("Remove stash"));
if (r != GTK_RESPONSE_ACCEPT)
{
return NULL;
}
GitgRepository *repository = gitg_window_get_repository (window);
gchar *spec = get_stash_refspec (repository, ref);
if (!spec)
{
return NULL;
}
if (!gitg_repository_commandv (repository,
NULL,
"reflog",
"delete",
"--updateref",
"--rewrite",
spec,
NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
_("Failed to remove stash"),
_("The stash item could not be successfully removed"),
NULL);
}
else
{
if (!gitg_repository_commandv (repository,
NULL,
"rev-parse",
"--verify",
"refs/stash@{0}",
NULL))
{
gchar *sha1 = gitg_utils_hash_to_sha1_new (gitg_ref_get_hash (ref));
gitg_repository_commandv (repository,
NULL,
"update-ref",
"-d",
"refs/stash",
sha1,
NULL);
g_free (sha1);
}
gitg_repository_reload (repository);
}
g_free (spec);
return NULL;
}
GitgRunner *
gitg_branch_actions_remove (GitgWindow *window,
GitgRef *ref)
@ -360,6 +463,8 @@ gitg_branch_actions_remove (GitgWindow *window,
case GITG_REF_TYPE_REMOTE:
ret = remove_remote_branch (window, cp);
break;
case GITG_REF_TYPE_STASH:
ret = remove_stash (window, cp);
default:
break;
}
@ -587,8 +692,12 @@ static gboolean
stash_changes (GitgWindow *window, gchar **ref, gboolean storeref)
{
if (no_changes (gitg_window_get_repository (window)))
{
if (ref)
{
*ref = NULL;
}
return TRUE;
}
@ -1126,11 +1235,80 @@ gitg_branch_actions_push_remote (GitgWindow *window,
gboolean
gitg_branch_actions_apply_stash (GitgWindow *window,
GitgRef *stash)
GitgRef *stash,
GitgRef *branch)
{
g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE);
g_return_val_if_fail (stash != NULL, FALSE);
g_return_val_if_fail (gitg_ref_get_ref_type (stash) == GITG_REF_TYPE_STASH, FALSE);
g_return_val_if_fail (gitg_ref_get_ref_type (branch) == GITG_REF_TYPE_BRANCH, FALSE);
gchar *message = g_strdup_printf (_("Are you sure you want to apply the stash item to local branch <%s>?"),
gitg_ref_get_shortname (branch));
if (message_dialog (window,
GTK_MESSAGE_QUESTION,
_("Apply stash"),
message,
_("Apply stash")) != GTK_RESPONSE_ACCEPT)
{
g_free (message);
return FALSE;
}
GitgRepository *repository = gitg_window_get_repository (window);
GitgRef *current = gitg_repository_get_current_working_ref (repository);
if (!gitg_ref_equal (branch, current))
{
if (!stash_changes (window, NULL, TRUE))
{
return FALSE;
}
if (!checkout_local_branch_real (window, branch))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
_("Failed to checkout local branch <%s>"),
NULL,
NULL,
gitg_ref_get_shortname (branch));
return FALSE;
}
}
gchar *sha1 = gitg_utils_hash_to_sha1_new (gitg_ref_get_hash (stash));
gboolean ret;
if (!gitg_repository_commandv (repository,
NULL,
"stash",
"apply",
"--index",
sha1,
NULL))
{
message = g_strdup_printf (_("The stash could not be applied to local branch <%s>"),
gitg_ref_get_shortname (branch));
message_dialog (window,
GTK_MESSAGE_ERROR,
_("Failed to apply stash"),
message,
NULL);
g_free (message);
ret = FALSE;
if (!gitg_ref_equal (current, branch) && no_changes (repository))
{
checkout_local_branch_real (window, current);
}
}
else
{
ret = TRUE;
gitg_repository_reload (repository);
}
return ret;
}

View file

@ -37,6 +37,7 @@ GitgRunner *gitg_branch_actions_rebase (GitgWindow *window, GitgRef *source, Git
GitgRunner *gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest);
GitgRunner *gitg_branch_actions_push_remote (GitgWindow *window, GitgRef *source, gchar const *remote);
gboolean gitg_branch_actions_apply_stash (GitgWindow *window, GitgRef *stash, GitgRef *branch);
G_END_DECLS
#endif /* __GITG_BRANCH_ACTIONS_H__ */

View file

@ -128,6 +128,7 @@ can_drag (GitgRef *ref)
{
case GITG_REF_TYPE_BRANCH:
case GITG_REF_TYPE_REMOTE:
case GITG_REF_TYPE_STASH:
return TRUE;
break;
default:
@ -155,6 +156,10 @@ can_drop (GitgRef *source, GitgRef *dest)
{
return dest_type == GITG_REF_TYPE_BRANCH;
}
else if (source_type == GITG_REF_TYPE_STASH)
{
return dest_type == GITG_REF_TYPE_BRANCH;
}
return FALSE;
}
@ -219,11 +224,6 @@ update_highlight (GitgDndData *data, gint x, gint y)
NULL,
NULL);
if (ref && !can_drag (ref))
{
ref = NULL;
}
if (ref != data->cursor_ref)
{
if (data->cursor_ref)
@ -231,7 +231,7 @@ update_highlight (GitgDndData *data, gint x, gint y)
gitg_ref_set_state (data->cursor_ref, GITG_REF_STATE_NONE);
}
if (ref)
if (ref && gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_NONE)
{
gitg_ref_set_state (ref, GITG_REF_STATE_PRELIGHT);

View file

@ -108,6 +108,11 @@ get_type_color (GitgRefType type, gdouble *r, gdouble *g, gdouble *b)
*g = 1;
*b = 0;
break;
case GITG_REF_TYPE_STASH:
*r = 1;
*g = 0.8;
*b = 0.5;
break;
default:
*r = 1;
*g = 1;

View file

@ -63,6 +63,11 @@
<property name="label">Push branch to...</property>
</object>
</child>
<child>
<object class="GtkAction" id="StashAction">
<property name="label">Apply stash to...</property>
</object>
</child>
</object>
</child>
<child>
@ -101,6 +106,9 @@
<menu name="Push" action="PushAction">
<placeholder name="Placeholder"/>
</menu>
<menu name="Stash" action="StashAction">
<placeholder name="Placeholder"/>
</menu>
</popup>
<popup name="dnd_popup">
<menuitem action="RebaseDndAction"/>

View file

@ -68,7 +68,8 @@ gitg_ref_new(gchar const *hash, gchar const *name)
PrefixTypeMap map[] = {
{"refs/heads/", GITG_REF_TYPE_BRANCH},
{"refs/remotes/", GITG_REF_TYPE_REMOTE},
{"refs/tags/", GITG_REF_TYPE_TAG}
{"refs/tags/", GITG_REF_TYPE_TAG},
{"refs/stash", GITG_REF_TYPE_STASH}
};
inst->prefix = NULL;
@ -83,7 +84,15 @@ gitg_ref_new(gchar const *hash, gchar const *name)
continue;
inst->type = map[i].type;
if (inst->type == GITG_REF_TYPE_STASH)
{
inst->shortname = g_strdup("stash");
}
else
{
inst->shortname = g_strdup(name + strlen(map[i].prefix));
}
if (map[i].type == GITG_REF_TYPE_REMOTE && (pos = strchr(inst->shortname, '/')))
{

View file

@ -37,7 +37,8 @@ typedef enum
GITG_REF_TYPE_NONE = 0,
GITG_REF_TYPE_BRANCH,
GITG_REF_TYPE_REMOTE,
GITG_REF_TYPE_TAG
GITG_REF_TYPE_TAG,
GITG_REF_TYPE_STASH
} GitgRefType;
typedef enum

View file

@ -550,6 +550,40 @@ on_loader_end_loading(GitgRunner *object, gboolean cancelled, GitgRepository *re
}
}
static gint
find_ref_custom (GitgRef *first, GitgRef *second)
{
return gitg_ref_equal (first, second) ? 0 : 1;
}
static GitgRef *
add_ref(GitgRepository *self, gchar const *sha1, gchar const *name)
{
GitgRef *ref = gitg_ref_new(sha1, name);
GSList *refs = (GSList *)g_hash_table_lookup(self->priv->refs,
gitg_ref_get_hash(ref));
if (refs == NULL)
{
g_hash_table_insert(self->priv->refs,
(gpointer)gitg_ref_get_hash(ref),
g_slist_append(NULL, ref));
}
else
{
if (!g_slist_find_custom (refs, ref, (GCompareFunc)find_ref_custom))
{
refs = g_slist_append(refs, ref);
}
else
{
gitg_ref_free (ref);
}
}
return ref;
}
static void
loader_update_stash(GitgRepository *repository, gchar **buffer)
{
@ -577,6 +611,8 @@ loader_update_stash(GitgRepository *repository, gchar **buffer)
gint64 timestamp = g_ascii_strtoll(components[3], NULL, 0);
GitgRevision *rv = gitg_revision_new(components[0], components[1], components[2], NULL, timestamp);
add_ref (repository, components[0], "refs/stash");
gitg_revision_set_sign(rv, 's');
append_revision(repository, rv);
g_strfreev(components);
@ -842,27 +878,6 @@ gitg_repository_get_loader(GitgRepository *self)
return GITG_RUNNER(g_object_ref(self->priv->loader));
}
static GitgRef *
add_ref(GitgRepository *self, gchar const *sha1, gchar const *name)
{
GitgRef *ref = gitg_ref_new(sha1, name);
GSList *refs = (GSList *)g_hash_table_lookup(self->priv->refs,
gitg_ref_get_hash(ref));
if (refs == NULL)
{
g_hash_table_insert(self->priv->refs,
(gpointer)gitg_ref_get_hash(ref),
g_slist_append(NULL, ref));
}
else
{
refs = g_slist_append(refs, ref);
}
return ref;
}
static gboolean
has_left_right(gchar const **av, int argc)
{
@ -986,9 +1001,6 @@ load_refs(GitgRepository *self)
gchar **components = g_strsplit(buf, " ", 3);
guint len = g_strv_length(components);
/* Skip refs/stash */
if (strcmp(components[0], "refs/stash") != 0)
{
if (len == 2 || len == 3)
{
gchar const *obj = len == 3 && *components[2] ? components[2] : components[1];
@ -999,7 +1011,6 @@ load_refs(GitgRepository *self)
self->priv->current_ref = gitg_ref_copy(ref);
}
}
}
g_strfreev(components);
}

View file

@ -312,12 +312,9 @@ on_renderer_path(GtkTreeViewColumn *column, GitgCellRendererPath *renderer, GtkT
GSList *labels;
const gchar *lbl = NULL;
switch (gitg_revision_get_sign(rv))
{
case 's':
lbl = "stash";
break;
case 't':
lbl = "staged";
break;
@ -475,21 +472,35 @@ update_dnd_status (GitgWindow *window, GitgRef *source, GitgRef *dest)
else
{
gchar *message = NULL;
GitgRefType source_type = gitg_ref_get_ref_type (source);
GitgRefType dest_type = gitg_ref_get_ref_type (dest);
if (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE)
if (source_type == GITG_REF_TYPE_BRANCH &&
dest_type== GITG_REF_TYPE_REMOTE)
{
message = g_strdup_printf (_("Push local branch <%s> to remote branch <%s>"), gitg_ref_get_shortname (source), gitg_ref_get_shortname (dest));
message = g_strdup_printf (_("Push local branch <%s> to remote branch <%s>"),
gitg_ref_get_shortname (source),
gitg_ref_get_shortname (dest));
}
else if (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH)
else if (source_type == GITG_REF_TYPE_BRANCH &&
dest_type == GITG_REF_TYPE_BRANCH)
{
message = g_strdup_printf (_("Merge/rebase local branch <%s> with/on local branch <%s>"), gitg_ref_get_shortname (source), gitg_ref_get_shortname (dest));
message = g_strdup_printf (_("Merge/rebase local branch <%s> with/on local branch <%s>"),
gitg_ref_get_shortname (source),
gitg_ref_get_shortname (dest));
}
else if (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_REMOTE &&
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH)
else if (source_type == GITG_REF_TYPE_REMOTE &&
dest_type == GITG_REF_TYPE_BRANCH)
{
message = g_strdup_printf (_("Merge/rebase local branch <%s> with/on remote branch <%s>"), gitg_ref_get_shortname (dest), gitg_ref_get_shortname (source));
message = g_strdup_printf (_("Merge/rebase local branch <%s> with/on remote branch <%s>"),
gitg_ref_get_shortname (dest),
gitg_ref_get_shortname (source));
}
else if (source_type == GITG_REF_TYPE_STASH &&
dest_type == GITG_REF_TYPE_BRANCH)
{
message = g_strdup_printf (_("Apply stash to local branch <%s>"),
gitg_ref_get_shortname (dest));
}
if (message)
@ -511,13 +522,22 @@ on_refs_dnd (GitgRef *source, GitgRef *dest, gboolean dropped, GitgWindow *windo
}
gboolean ret = FALSE;
GitgRefType source_type = gitg_ref_get_ref_type (source);
GitgRefType dest_type = gitg_ref_get_ref_type (dest);
if (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE)
if (source_type == GITG_REF_TYPE_BRANCH &&
dest_type == GITG_REF_TYPE_REMOTE)
{
ret = add_branch_action (window, gitg_branch_actions_push (window, source, dest));
}
else if (gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH)
else if (source_type == GITG_REF_TYPE_STASH)
{
if (dest_type == GITG_REF_TYPE_BRANCH)
{
ret = gitg_branch_actions_apply_stash (window, source, dest);
}
}
else if (dest_type == GITG_REF_TYPE_BRANCH)
{
GtkWidget *popup = gtk_ui_manager_get_widget (window->priv->menus_ui_manager,
"/ui/dnd_popup");
@ -976,6 +996,33 @@ fill_branches_combo(GitgWindow *window)
g_slist_free(refs);
}
static void
update_window_title (GitgWindow *window)
{
if (!window->priv->repository)
{
gtk_window_set_title (GTK_WINDOW (window), _("gitg"));
return;
}
GitgRef *ref = gitg_repository_get_current_working_ref (window->priv->repository);
gchar *refname = NULL;
if (ref)
{
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);
gtk_window_set_title(GTK_WINDOW(window), title);
g_free(basename);
g_free(title);
g_free (refname);
}
static void
on_repository_load(GitgRepository *repository, GitgWindow *window)
{
@ -983,6 +1030,8 @@ on_repository_load(GitgRepository *repository, GitgWindow *window)
clear_branches_combo(window);
fill_branches_combo(window);
g_signal_handlers_unblock_by_func(window->priv->combo_branches, on_branches_combo_changed, window);
update_window_title (window);
}
static void
@ -1062,13 +1111,6 @@ load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **
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 *basename = g_path_get_basename(gitg_repository_get_path(window->priv->repository));
gchar *title = g_strdup_printf("%s - %s", _("gitg"), basename);
gtk_window_set_title(GTK_WINDOW(window), title);
g_free(basename);
g_free(title);
add_recent_item(window);
gtk_widget_set_sensitive(GTK_WIDGET(window->priv->notebook_main), TRUE);
}
@ -1081,7 +1123,7 @@ load_repository(GitgWindow *window, gchar const *path, gint argc, gchar const **
if (path || argc > 1)
handle_no_gitdir(window);
gtk_window_set_title(GTK_WINDOW(window), _("gitg"));
update_window_title (window);
gtk_widget_set_sensitive(GTK_WIDGET(window->priv->notebook_main), FALSE);
}
}
@ -1449,6 +1491,15 @@ on_merge_activated (GtkAction *action, GitgWindow *window)
window->priv->popup_refs[0]));
}
static void
on_stash_activated (GtkAction *action, GitgWindow *window)
{
GitgRef *dest = g_object_get_data (G_OBJECT (action),
DYNAMIC_ACTION_DATA_KEY);
gitg_branch_actions_apply_stash (window, window->priv->popup_refs[0], dest);
}
static void
update_merge_rebase (GitgWindow *window, GitgRef *ref)
{
@ -1473,7 +1524,8 @@ update_merge_rebase (GitgWindow *window, GitgRef *ref)
g_list_free (actions);
}
if (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH)
if (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_STASH)
{
return;
}
@ -1503,6 +1555,8 @@ update_merge_rebase (GitgWindow *window, GitgRef *ref)
{
gchar const *rname = gitg_ref_get_shortname (r);
if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH)
{
gchar *rebase = g_strconcat ("Rebase", rname, "Action", NULL);
gchar *merge = g_strconcat ("Merge", rname, "Action", NULL);
@ -1555,11 +1609,45 @@ update_merge_rebase (GitgWindow *window, GitgRef *ref)
g_object_unref (rebaseac);
g_object_unref (mergeac);
}
else
{
gchar *stash = g_strconcat ("Stash", rname, "Action", NULL);
GtkAction *stashac = gtk_action_new (stash, rname, NULL, NULL);
g_object_set_data_full (G_OBJECT (stashac),
DYNAMIC_ACTION_DATA_KEY,
gitg_ref_copy (r),
(GDestroyNotify)gitg_ref_free);
g_signal_connect (stashac,
"activate",
G_CALLBACK (on_stash_activated),
window);
gtk_action_group_add_action (ac, stashac);
gchar *name = g_strconcat ("Stash", rname, NULL);
gtk_ui_manager_add_ui (window->priv->menus_ui_manager,
window->priv->merge_rebase_uid,
"/ui/revision_popup/Stash/Placeholder",
name,
stash,
GTK_UI_MANAGER_MENUITEM,
FALSE);
g_free (name);
g_object_unref (stashac);
}
}
}
g_slist_foreach (refs, (GFunc)gitg_ref_free, NULL);
g_slist_free (refs);
if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH)
{
gchar **remotes = gitg_repository_get_remotes (window->priv->repository);
gchar **ptr = remotes;
@ -1592,6 +1680,7 @@ update_merge_rebase (GitgWindow *window, GitgRef *ref)
}
g_strfreev (remotes);
}
gtk_ui_manager_ensure_update (window->priv->menus_ui_manager);
}
@ -1663,7 +1752,8 @@ popup_revision (GitgWindow *window, GdkEventButton *event)
gtk_tree_path_free (path);
if (!ref || (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_REMOTE))
gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_REMOTE &&
gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_STASH))
{
return FALSE;
}
@ -1703,6 +1793,11 @@ popup_revision (GitgWindow *window, GdkEventButton *event)
gtk_action_set_visible (checkout, !gitg_ref_equal (working, ref));
}
else if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_STASH)
{
gtk_action_set_label (remove, _("Remove stash"));
gtk_action_set_visible (checkout, FALSE);
}
update_merge_rebase (window, ref);
window->priv->popup_refs[0] = ref;
@ -1726,7 +1821,10 @@ on_tree_view_rv_button_press_event (GtkWidget *widget, GdkEventButton *event, Gi
void
on_checkout_branch_action_activate (GtkAction *action, GitgWindow *window)
{
gitg_branch_actions_checkout (window, window->priv->popup_refs[0]);
if (gitg_branch_actions_checkout (window, window->priv->popup_refs[0]))
{
update_window_title (window);
}
}
void