[gitg] Implemented 'amend' commit
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: svn-commits-list gnome org
- Subject: [gitg] Implemented 'amend' commit
- Date: Sun, 5 Jul 2009 17:40:16 +0000 (UTC)
commit c9815fb2aaf17bbff1e2a61e96c8da2ecdd60191
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Sun Jul 5 14:21:45 2009 +0200
Implemented 'amend' commit
gitg/gitg-commit-view.c | 41 +++++++++++-
gitg/gitg-commit.c | 169 ++++++++++++++++++++++++++++++++++++++++++++---
gitg/gitg-commit.h | 4 +-
gitg/gitg-window.ui | 51 +++++++++++---
4 files changed, 240 insertions(+), 25 deletions(-)
---
diff --git a/gitg/gitg-commit-view.c b/gitg/gitg-commit-view.c
index 6f90062..0ee44c3 100644
--- a/gitg/gitg-commit-view.c
+++ b/gitg/gitg-commit-view.c
@@ -72,6 +72,7 @@ struct _GitgCommitViewPrivate
GtkSourceView *changes_view;
GtkTextView *comment_view;
GtkCheckButton *check_button_signed_off_by;
+ GtkCheckButton *check_button_amend;
GtkHScale *hscale_context;
gint context_size;
@@ -123,6 +124,7 @@ static void on_revert_changes(GtkAction *action, GitgCommitView *view);
static void on_ignore_file(GtkAction *action, GitgCommitView *view);
static void on_unstage_changes(GtkAction *action, GitgCommitView *view);
+static void on_check_button_amend_toggled (GtkToggleButton *button, GitgCommitView *view);
static void
gitg_commit_view_finalize(GObject *object)
@@ -936,7 +938,8 @@ gitg_commit_view_parser_finished(GtkBuildable *buildable, GtkBuilder *builder)
self->priv->changes_view = GTK_SOURCE_VIEW(gtk_builder_get_object(builder, "source_view_changes"));
self->priv->comment_view = GTK_TEXT_VIEW(gtk_builder_get_object(builder, "text_view_comment"));
self->priv->check_button_signed_off_by = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "check_button_signed_off_by"));
-
+ self->priv->check_button_amend = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "check_button_amend"));
+
GitgPreferences *preferences = gitg_preferences_get_default();
gitg_data_binding_new(preferences, "message-show-right-margin",
@@ -1004,6 +1007,11 @@ gitg_commit_view_parser_finished(GtkBuildable *buildable, GtkBuilder *builder)
g_signal_connect(gtk_builder_get_object(builder, "button_commit"), "clicked", G_CALLBACK(on_commit_clicked), self);
g_signal_connect(self->priv->hscale_context, "value-changed", G_CALLBACK(on_context_value_changed), self);
+
+ g_signal_connect (self->priv->check_button_amend,
+ "toggled",
+ G_CALLBACK (on_check_button_amend_toggled),
+ self);
}
static void
@@ -1433,10 +1441,11 @@ on_commit_clicked(GtkButton *button, GitgCommitView *view)
}
gboolean signoff = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(view->priv->check_button_signed_off_by));
-
+ gboolean amend = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->priv->check_button_amend));
+
GError *error = NULL;
- if (!gitg_commit_commit(view->priv->commit, comment, signoff, &error))
+ if (!gitg_commit_commit(view->priv->commit, comment, signoff, amend, &error))
{
if (error && error->domain == GITG_COMMIT_ERROR && error->code == GITG_COMMIT_ERROR_SIGNOFF)
show_error(view, _("Your user name or email could not be retrieved for use in the sign off message"));
@@ -1449,6 +1458,8 @@ on_commit_clicked(GtkButton *button, GitgCommitView *view)
else
{
gtk_text_buffer_set_text(gtk_text_view_get_buffer(view->priv->comment_view), "", -1);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->check_button_amend), FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->check_button_signed_off_by), FALSE);
}
g_free(comment);
@@ -1681,3 +1692,27 @@ on_changes_view_popup_menu(GtkTextView *textview, GtkMenu *menu, GitgCommitView
gtk_menu_shell_append(GTK_MENU_SHELL(menu), revert);
}
}
+
+static void
+on_check_button_amend_toggled (GtkToggleButton *button, GitgCommitView *view)
+{
+ gboolean active = gtk_toggle_button_get_active (button);
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (view->priv->comment_view);
+ GtkTextIter start;
+ GtkTextIter end;
+
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+
+ if (active && gtk_text_iter_compare (&start, &end) == 0)
+ {
+ // Get last commit message
+ gchar *message = gitg_commit_amend_message (view->priv->commit);
+
+ if (message)
+ {
+ gtk_text_buffer_set_text (buffer, message, -1);
+ }
+
+ g_free (message);
+ }
+}
diff --git a/gitg/gitg-commit.c b/gitg/gitg-commit.c
index ea4cf5d..4382ac0 100644
--- a/gitg/gitg-commit.c
+++ b/gitg/gitg-commit.c
@@ -710,8 +710,69 @@ get_signed_off_line(GitgCommit *commit)
return ret;
}
+static void
+on_commit_tree_update (GitgRunner *runner, gchar **lines, GString *buffer)
+{
+ while (lines && *lines)
+ {
+ if (buffer->len != 0)
+ {
+ g_string_append_c (buffer, '\n');
+ }
+
+ g_string_append (buffer, *lines);
+ ++lines;
+ }
+}
+
+static void
+set_amend_environment (GitgCommit *commit, GitgRunner *runner)
+{
+ gchar **out;
+
+ out = gitg_repository_command_with_outputv (commit->priv->repository,
+ NULL,
+ "cat-file",
+ "commit",
+ "HEAD",
+ NULL);
+
+ // Parse author
+ GRegex *r = g_regex_new ("^author (.*) <([^>]*)> ([0-9]+.*)$",
+ G_REGEX_CASELESS,
+ 0,
+ NULL);
+
+ GMatchInfo *info = NULL;
+ gchar **ptr = out;
+
+ while (ptr && *ptr)
+ {
+ if (g_regex_match (r, *ptr, 0, &info))
+ {
+ gchar *name = g_match_info_fetch (info, 1);
+ gchar *email = g_match_info_fetch (info, 2);
+ gchar *date = g_match_info_fetch (info, 3);
+
+ gitg_runner_add_environment (runner, "GIT_AUTHOR_NAME", name);
+ gitg_runner_add_environment (runner, "GIT_AUTHOR_EMAIL", email);
+ gitg_runner_add_environment (runner, "GIT_AUTHOR_DATE", date);
+
+ g_free (name);
+ g_free (email);
+ g_free (date);
+
+ break;
+ }
+
+ ++ptr;
+ }
+
+ g_strfreev (out);
+}
+
static gboolean
-commit_tree(GitgCommit *commit, gchar const *tree, gchar const *comment, gboolean signoff, gchar **ref, GError **error)
+commit_tree(GitgCommit *commit, gchar const *tree, gchar const *comment, gboolean signoff, gboolean amend, gchar **ref, GError **error)
{
gchar *fullcomment;
@@ -734,21 +795,47 @@ commit_tree(GitgCommit *commit, gchar const *tree, gchar const *comment, gboolea
fullcomment = g_strdup(comment);
}
- gchar *head = gitg_repository_parse_ref(commit->priv->repository, "HEAD");
-
- gchar **lines = gitg_repository_command_with_input_and_outputv(commit->priv->repository, fullcomment, error, "commit-tree", tree, head ? "-p" : NULL, head, NULL);
+ gchar *head;
+
+ if (amend)
+ {
+ head = gitg_repository_parse_ref(commit->priv->repository, "HEAD^");
+ }
+ else
+ {
+ head = gitg_repository_parse_ref(commit->priv->repository, "HEAD");
+ }
+
+ GitgRunner *runner = gitg_runner_new_synchronized (1000);
+ GString *buffer = g_string_new ("");
+
+ if (amend)
+ {
+ set_amend_environment (commit, runner);
+ }
+
+ g_signal_connect (runner, "update", G_CALLBACK (on_commit_tree_update), buffer);
+ gitg_repository_run_command_with_inputv (commit->priv->repository,
+ runner,
+ fullcomment,
+ error,
+ "commit-tree",
+ tree,
+ head ? "-p" : NULL,
+ head,
+ NULL);
g_free(head);
g_free(fullcomment);
+ g_object_unref (runner);
- if (!lines || strlen(*lines) != HASH_SHA_SIZE)
+ if (buffer->len != HASH_SHA_SIZE)
{
- g_strfreev(lines);
+ g_string_free(buffer, TRUE);
return FALSE;
}
- *ref = g_strdup(*lines);
- g_strfreev(lines);
+ *ref = g_string_free (buffer, FALSE);
return TRUE;
}
@@ -760,16 +847,24 @@ update_ref(GitgCommit *commit, gchar const *ref, gchar const *subject, GError **
}
gboolean
-gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, GError **error)
+gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, gboolean amend, GError **error)
{
g_return_val_if_fail(GITG_IS_COMMIT(commit), FALSE);
gchar *tree;
+
if (!write_tree(commit, &tree, error))
return FALSE;
+ gchar *path = g_build_filename (gitg_repository_get_path (commit->priv->repository),
+ ".git",
+ "COMMIT_EDITMSG",
+ NULL);
+ g_file_set_contents (path, comment, -1, NULL);\
+ g_free (path);
+
gchar *ref;
- gboolean ret = commit_tree(commit, tree, comment, signoff, &ref, error);
+ gboolean ret = commit_tree(commit, tree, comment, signoff, amend, &ref, error);
g_free(tree);
if (!ret)
@@ -889,3 +984,57 @@ gitg_commit_find_changed_file(GitgCommit *commit, GFile *file)
return NULL;
}
}
+
+gchar *
+gitg_commit_amend_message (GitgCommit *commit)
+{
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), NULL);
+
+ gchar **out;
+
+ out = gitg_repository_command_with_outputv (commit->priv->repository,
+ NULL,
+ "cat-file",
+ "commit",
+ "HEAD",
+ NULL);
+
+ gchar *ret = NULL;
+
+ if (out)
+ {
+ gchar **ptr = out;
+
+ while (*ptr)
+ {
+ if (!**ptr)
+ {
+ ++ptr;
+ break;
+ }
+
+ ++ptr;
+ }
+
+ if (*ptr && **ptr)
+ {
+ GString *buffer = g_string_new ("");
+
+ while (*ptr)
+ {
+ if (buffer->len != 0)
+ {
+ g_string_append_c (buffer, '\n');
+ }
+
+ g_string_append (buffer, *ptr);
+ ++ptr;
+ }
+
+ ret = g_string_free (buffer, FALSE);
+ }
+ }
+
+ g_strfreev (out);
+ return ret;
+}
diff --git a/gitg/gitg-commit.h b/gitg/gitg-commit.h
index d37fc2f..600ee5c 100644
--- a/gitg/gitg-commit.h
+++ b/gitg/gitg-commit.h
@@ -72,13 +72,15 @@ gboolean gitg_commit_stage(GitgCommit *commit, GitgChangedFile *file, gchar cons
gboolean gitg_commit_unstage(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error);
gboolean gitg_commit_has_changes(GitgCommit *commit);
-gboolean gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, GError **error);
+gboolean gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, gboolean amend, GError **error);
gboolean gitg_commit_revert(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error);
gboolean gitg_commit_add_ignore(GitgCommit *commit, GitgChangedFile *file, GError **error);
GitgChangedFile *gitg_commit_find_changed_file(GitgCommit *commit, GFile *file);
+gchar *gitg_commit_amend_message (GitgCommit *commit);
+
G_END_DECLS
#endif /* __GITG_COMMIT_H__ */
diff --git a/gitg/gitg-window.ui b/gitg/gitg-window.ui
index 99b4136..125a3b6 100644
--- a/gitg/gitg-window.ui
+++ b/gitg/gitg-window.ui
@@ -708,27 +708,56 @@
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
- <object class="GtkCheckButton" id="check_button_signed_off_by">
- <property name="label" translatable="yes">Add signed-off-by</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="check_button_amend">
+ <property name="label" translatable="yes">Amend</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_button_signed_off_by">
+ <property name="label" translatable="yes">Add signed-off-by</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="button_commit">
- <property name="label" translatable="yes">Commit</property>
+ <object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="image">image_commit</property>
+ <property name="yalign">1</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkButton" id="button_commit">
+ <property name="label" translatable="yes">Commit</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image_commit</property>
+ </object>
+ </child>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]