From: Christian Couder <chriscool@tuxfamily.org>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org,
Johannes Schindelin <Johannes.Schindelin@gmx.de>,
Stephan Beyer <s-beyer@gmx.net>,
Daniel Barkalow <barkalow@iabervon.org>,
Jakub Narebski <jnareb@gmail.com>
Subject: [PATCH v4 13/15] sequencer: add "do_commit()" and related functions working on "next_commit"
Date: Fri, 28 Aug 2009 06:47:43 +0200 [thread overview]
Message-ID: <20090828044746.4307.51257.chriscool@tuxfamily.org> (raw)
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
This patch adds "struct commit_info", the "next_commit" static variable
and the following functions:
- do_commit()
- set_author_info()
- set_message_source()
- set_pick_subject()
- write_commit_summary_into()
This makes it possible to prepare and perform a commit (without forking
and execing "git commit"), and this will be used in a following patch to
perform a cherry-pick.
All these functions work on the "struct commit_info next_commit" global.
This variable will eventually be saved between the different calls to
"git rebase" (or "git sequencer"). So we cannot easily reuse existing
functions from "builtin-commit.c" or "builtin-commit-tree.c" and we need
these special functions.
This patch adds some code that comes from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
Compared to the sequencer project, the only change is that "mark"
related (3 lines long) code has been removed from do_commit().
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-sequencer--helper.c | 213 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 213 insertions(+), 0 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index 71a7fef..014e4ce 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -5,17 +5,55 @@
#include "refs.h"
#include "diff.h"
#include "unpack-trees.h"
+#include "string-list.h"
+#include "pick.h"
+#include "rerere.h"
+#include "dir.h"
+#include "cache-tree.h"
+#include "utf8.h"
#define SEQ_DIR "rebase-merge"
#define PATCH_FILE git_path(SEQ_DIR "/patch")
+#define MERGE_MSG git_path("MERGE_MSG")
+#define SQUASH_MSG git_path("SQUASH_MSG")
+
+/**********************************************************************
+ * Data structures
+ */
+
+struct user_info {
+ const char *name;
+ const char *mail;
+ const char *time; /* "<timestamp> <timezone>" */
+};
+
+struct commit_info {
+ struct user_info author; /* author info */
+ struct user_info committer; /* not used, but for easy extendability */
+ const char *encoding; /* encoding */
+ char *subject; /* basically the first line of the summary */
+ struct strbuf summary; /* the commit message */
+ char *source; /* source of the commit message, either
+ * "message", "merge", "squash" or a commit SHA1 */
+ char *patch; /* a patch */
+ struct string_list parents; /* list of parents' hex'ed sha1 ids */
+};
+
+/**********************************************************************
+ * Global variables
+ */
static char *reflog;
+static int squash_count = 0;
+
static int allow_dirty = 0, verbosity = 1, advice = 1;
static unsigned char head_sha1[20];
+static struct commit_info next_commit;
+
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
"git sequencer--helper --reset-hard <commit> <reflog-msg> "
@@ -25,6 +63,10 @@ static const char * const git_sequencer_helper_usage[] = {
NULL
};
+/**********************************************************************
+ * Sequencer functions
+ */
+
static int parse_and_init_tree_desc(const unsigned char *sha1,
struct tree_desc *desc)
{
@@ -162,6 +204,157 @@ static void make_patch(struct commit *commit)
free(args);
}
+/* Commit current index with information next_commit onto parent_sha1. */
+static int do_commit(unsigned char *parent_sha1)
+{
+ int failed;
+ unsigned char tree_sha1[20];
+ unsigned char commit_sha1[20];
+ struct strbuf sbuf;
+ const char *reencoded = NULL;
+
+ if (squash_count) {
+ squash_count = 0;
+ if (file_exists(SQUASH_MSG))
+ unlink(SQUASH_MSG);
+ }
+
+ if (!index_differs_from("HEAD", 0) &&
+ !next_commit.parents.nr)
+ return error("No changes! Do you really want an empty commit?");
+
+ if (!next_commit.author.name || !next_commit.author.mail)
+ return error("Internal error: Author information not set properly.");
+
+ if (write_cache_as_tree(tree_sha1, 0, NULL))
+ return 1;
+
+ if (!next_commit.encoding)
+ next_commit.encoding = xstrdup("utf-8");
+ if (!git_commit_encoding)
+ git_commit_encoding = "utf-8";
+
+ strbuf_init(&sbuf, 8192); /* should avoid reallocs for the headers */
+ strbuf_addf(&sbuf, "tree %s\n", sha1_to_hex(tree_sha1));
+ if (parent_sha1)
+ strbuf_addf(&sbuf, "parent %s\n", sha1_to_hex(parent_sha1));
+ if (next_commit.parents.nr) {
+ int i;
+ for (i = 0; i < next_commit.parents.nr; ++i)
+ strbuf_addf(&sbuf, "parent %s\n",
+ next_commit.parents.items[i].string);
+ }
+ if (!next_commit.author.time) {
+ char time[50];
+ datestamp(time, sizeof(time));
+ next_commit.author.time = xstrdup(time);
+ }
+
+ stripspace(&next_commit.summary, 1);
+
+ /* if encodings differ, reencode whole buffer */
+ if (strcasecmp(git_commit_encoding, next_commit.encoding)) {
+ if ((reencoded = reencode_string(next_commit.author.name,
+ git_commit_encoding, next_commit.encoding))) {
+ free((void *)next_commit.author.name);
+ next_commit.author.name = reencoded;
+ }
+ if ((reencoded = reencode_string(next_commit.summary.buf,
+ git_commit_encoding, next_commit.encoding))) {
+ strbuf_reset(&next_commit.summary);
+ strbuf_addstr(&next_commit.summary, reencoded);
+ }
+ }
+ strbuf_addf(&sbuf, "author %s <%s> %s\n", next_commit.author.name,
+ next_commit.author.mail, next_commit.author.time);
+ strbuf_addf(&sbuf, "committer %s\n", git_committer_info(0));
+ if (!is_encoding_utf8(git_commit_encoding))
+ strbuf_addf(&sbuf, "encoding %s\n", git_commit_encoding);
+ strbuf_addch(&sbuf, '\n');
+ strbuf_addbuf(&sbuf, &next_commit.summary);
+ if (sbuf.buf[sbuf.len-1] != '\n')
+ strbuf_addch(&sbuf, '\n');
+
+ failed = write_sha1_file(sbuf.buf, sbuf.len, commit_type, commit_sha1);
+ strbuf_release(&sbuf);
+ if (failed)
+ return 1;
+
+ if (verbosity > 1)
+ printf("Created %scommit %s\n",
+ parent_sha1 || next_commit.parents.nr ? "" : "initial ",
+ sha1_to_hex(commit_sha1));
+
+ if (update_ref(reflog, "HEAD", commit_sha1, NULL, 0, 0))
+ return error("Could not update HEAD to %s.",
+ sha1_to_hex(commit_sha1));
+
+ return 0;
+}
+
+/*
+ * Fill next_commit.author according to ident.
+ * Ident may have one of the following forms:
+ * "name <e-mail> timestamp timezone\n..."
+ * "name <e-mail> timestamp timezone"
+ * "name <e-mail>"
+ */
+static void set_author_info(const char *ident)
+{
+ const char *tmp1 = strstr(ident, " <");
+ const char *tmp2;
+ char *data;
+ if (!tmp1)
+ return;
+ tmp2 = strstr(tmp1+2, ">");
+ if (!tmp2)
+ return;
+ if (tmp2[1] != 0 && tmp2[1] != ' ')
+ return;
+
+ data = xmalloc(strlen(ident)); /* a trivial upper bound */
+
+ snprintf(data, tmp1-ident+1, "%s", ident);
+ next_commit.author.name = xstrdup(data);
+ snprintf(data, tmp2-tmp1-1, "%s", tmp1+2);
+ next_commit.author.mail = xstrdup(data);
+
+ if (tmp2[1] == 0) {
+ free(data);
+ return;
+ }
+
+ tmp1 = strpbrk(tmp2+2, "\r\n");
+ if (!tmp1)
+ tmp1 = tmp2 + strlen(tmp2);
+
+ snprintf(data, tmp1-tmp2-1, "%s", tmp2+2);
+ next_commit.author.time = xstrdup(data);
+ free(data);
+}
+
+static void set_message_source(const char *source)
+{
+ if (next_commit.source)
+ free(next_commit.source);
+ next_commit.source = xstrdup(source);
+}
+
+/* Set subject, an information for the case of conflict */
+static void set_pick_subject(const char *hex, struct commit *commit)
+{
+ const char *tmp = strstr(commit->buffer, "\n\n");
+ if (tmp) {
+ const char *eol;
+ int len = strlen(hex);
+ tmp += 2;
+ eol = strchrnul(tmp, '\n');
+ next_commit.subject = xmalloc(eol - tmp + len + 5);
+ snprintf(next_commit.subject, eol - tmp + len + 5, "%s... %s",
+ hex, tmp);
+ }
+}
+
/* Return a commit object of "arg" */
static struct commit *get_commit(const char *arg)
{
@@ -198,6 +391,26 @@ static int set_verbosity(int verbose)
return 0;
}
+static int write_commit_summary_into(const char *filename)
+{
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+ int fd = hold_lock_file_for_update(lock, filename, 0);
+ if (fd < 0)
+ return error("Unable to create '%s.lock': %s", filename,
+ strerror(errno));
+ if (write_in_full(fd, next_commit.summary.buf,
+ next_commit.summary.len) < 0)
+ return error("Could not write to %s: %s",
+ filename, strerror(errno));
+ if (commit_lock_file(lock) < 0)
+ return error("Error wrapping up %s", filename);
+ return 0;
+}
+
+/**********************************************************************
+ * Builtin sequencer helper functions
+ */
+
/* v should be "" or "t" or "\d" */
static int parse_verbosity(const char *v)
{
--
1.6.4.271.ge010d
next prev parent reply other threads:[~2009-08-28 5:00 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-28 4:47 [PATCH v4 00/15] complete reroll of my "port rebase -i to C" series Christian Couder
2009-08-28 4:47 ` [PATCH v4 01/15] sequencer: add "builtin-sequencer--helper.c" Christian Couder
2009-08-28 4:47 ` [PATCH v4 02/15] sequencer: add "make_patch" function to save a patch Christian Couder
2009-08-28 4:47 ` [PATCH v4 03/15] rebase -i: use "git sequencer--helper --make-patch" Christian Couder
2009-08-28 4:47 ` [PATCH v4 04/15] sequencer: add "reset_almost_hard()" and related functions Christian Couder
2009-08-28 6:08 ` Eric Raible
2009-08-28 4:47 ` [PATCH v4 05/15] sequencer: add "--reset-hard" option to "git sequencer--helper" Christian Couder
2009-08-28 4:47 ` [PATCH v4 06/15] rebase -i: use "git sequencer--helper --reset-hard" Christian Couder
2009-08-28 4:47 ` [PATCH v4 07/15] sequencer: add "do_fast_forward()" to perform a fast forward Christian Couder
2009-08-28 4:47 ` [PATCH v4 08/15] sequencer: add "--fast-forward" option to "git sequencer--helper" Christian Couder
2009-08-28 4:47 ` [PATCH v4 09/15] sequencer: let "git sequencer--helper" callers set "allow_dirty" Christian Couder
2009-08-28 4:47 ` [PATCH v4 10/15] rebase -i: use "git sequencer--helper --fast-forward" Christian Couder
2009-08-28 4:47 ` [PATCH v4 11/15] revert: libify cherry-pick and revert functionnality Christian Couder
2009-08-28 4:47 ` [PATCH v4 12/15] pick: libify "pick_help_msg()" Christian Couder
2009-08-28 4:47 ` Christian Couder [this message]
2009-08-28 4:47 ` [PATCH v4 14/15] sequencer: add "--cherry-pick" option to "git sequencer--helper" Christian Couder
2009-08-28 4:47 ` [PATCH v4 15/15] rebase -i: use "git sequencer--helper --cherry-pick" Christian Couder
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090828044746.4307.51257.chriscool@tuxfamily.org \
--to=chriscool@tuxfamily.org \
--cc=Johannes.Schindelin@gmx.de \
--cc=barkalow@iabervon.org \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jnareb@gmail.com \
--cc=s-beyer@gmx.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).