diff options
author | Junio C Hamano <gitster@pobox.com> | 2011-11-08 15:38:07 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2011-11-09 22:27:11 -0800 |
commit | ed7a42a0752fd71cf04273b8e691966dd2c33ebe (patch) | |
tree | 222f7e6815eecc11fb319526172e275e15d75ae5 | |
parent | fab47d057559301c74d6642576694fd251a3fd11 (diff) | |
download | git-ed7a42a0752fd71cf04273b8e691966dd2c33ebe.tar.gz |
commit: teach --amend to carry forward extra headers
After running "git pull $there for-linus" to merge a signed tag, the
integrator may need to amend the resulting merge commit to fix typoes
in it. Teach --amend option to read the existing extra headers, and
carry them forward.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | builtin/commit.c | 9 | ||||
-rw-r--r-- | commit.c | 67 | ||||
-rw-r--r-- | commit.h | 3 |
3 files changed, 76 insertions, 3 deletions
diff --git a/builtin/commit.c b/builtin/commit.c index 4688a738f7..fca7ea01f3 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1382,6 +1382,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) int allow_fast_forward = 1; struct wt_status s; struct commit *current_head = NULL; + struct commit_extra_header *extra = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1483,12 +1484,16 @@ int cmd_commit(int argc, const char **argv, const char *prefix) exit(1); } - if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1, - author_ident.buf)) { + if (amend) + extra = read_commit_extra_headers(current_head); + + if (commit_tree_extended(sb.buf, active_cache_tree->sha1, parents, sha1, + author_ident.buf, extra)) { rollback_index_files(); die(_("failed to write commit object")); } strbuf_release(&author_ident); + free_commit_extra_headers(extra); ref_lock = lock_any_ref_for_update("HEAD", !current_head @@ -894,7 +894,72 @@ static void add_extra_header(struct strbuf *buffer, struct commit_extra_header *extra) { strbuf_addstr(buffer, extra->key); - strbuf_add_lines(buffer, " ", extra->value, extra->len); + if (extra->len) + strbuf_add_lines(buffer, " ", extra->value, extra->len); + else + strbuf_addch(buffer, '\n'); +} + +struct commit_extra_header *read_commit_extra_headers(struct commit *commit) +{ + struct commit_extra_header *extra = NULL; + unsigned long size; + enum object_type type; + char *buffer = read_sha1_file(commit->object.sha1, &type, &size); + if (buffer && type == OBJ_COMMIT) + extra = read_commit_extra_header_lines(buffer, size); + free(buffer); + return extra; +} + +static inline int standard_header_field(const char *field, size_t len) +{ + return ((len == 4 && !memcmp(field, "tree ", 5)) || + (len == 6 && !memcmp(field, "parent ", 7)) || + (len == 6 && !memcmp(field, "author ", 7)) || + (len == 9 && !memcmp(field, "committer ", 10)) || + (len == 8 && !memcmp(field, "encoding ", 9))); +} + +struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size) +{ + struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL; + const char *line, *next, *eof, *eob; + struct strbuf buf = STRBUF_INIT; + + for (line = buffer, eob = line + size; + line < eob && *line != '\n'; + line = next) { + next = memchr(line, '\n', eob - line); + next = next ? next + 1 : eob; + if (*line == ' ') { + /* continuation */ + if (it) + strbuf_add(&buf, line + 1, next - (line + 1)); + continue; + } + if (it) + it->value = strbuf_detach(&buf, &it->len); + strbuf_reset(&buf); + it = NULL; + + eof = strchr(line, ' '); + if (next <= eof) + eof = next; + + if (standard_header_field(line, eof - line)) + continue; + + it = xcalloc(1, sizeof(*it)); + it->key = xmemdupz(line, eof-line); + *tail = it; + tail = &it->next; + if (eof + 1 < next) + strbuf_add(&buf, eof + 1, next - (eof + 1)); + } + if (it) + it->value = strbuf_detach(&buf, &it->len); + return extra; } void free_commit_extra_headers(struct commit_extra_header *extra) @@ -200,6 +200,9 @@ extern int commit_tree_extended(const char *msg, unsigned char *tree, const char *author, struct commit_extra_header *); +extern struct commit_extra_header *read_commit_extra_headers(struct commit *); +extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len); + extern void free_commit_extra_headers(struct commit_extra_header *extra); struct merge_remote_desc { |