diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-02-10 23:50:41 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-02-10 23:50:41 +0100 |
commit | 97645461d8bc74f95080697c1b111894698360c8 (patch) | |
tree | 19f8ae3f922c593336e96740436d5416630b62f1 | |
parent | b362fbf363f1793fe9b190f57ecb04afd26b09ce (diff) | |
download | libgit2-cmn/safe-commit.tar.gz |
commit: add a function to create a commit on top of a refcmn/safe-commit
Add a way to safely create a commit which builds on top of the current
commit in a given reference.
-rw-r--r-- | include/git2/commit.h | 19 | ||||
-rw-r--r-- | src/commit.c | 72 | ||||
-rw-r--r-- | tests/commit/write.c | 27 |
3 files changed, 109 insertions, 9 deletions
diff --git a/include/git2/commit.h b/include/git2/commit.h index 834330b5d..78deb6de0 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -351,6 +351,25 @@ GIT_EXTERN(int) git_commit_amend( const char *message, const git_tree *tree); +/** + * Create a commit on top of the tip of a given branch + * + * All parameters have the same meaning as in `git_commit_create()` + * with the exception that `update_ref` is required and the new + * commit's single parent will be the value of that ref at the time of + * reading. + */ +int git_commit_append( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree); + + /** @} */ GIT_END_DECL #endif diff --git a/src/commit.c b/src/commit.c index de50e772e..6eb4f443b 100644 --- a/src/commit.c +++ b/src/commit.c @@ -16,6 +16,7 @@ #include "commit.h" #include "signature.h" #include "message.h" +#include "refs.h" #include <stdarg.h> @@ -36,6 +37,25 @@ void git_commit__free(void *_commit) git__free(commit); } +static int commit_reflog_message(git_buf *buf, git_repository *repo, const git_oid *id) +{ + git_commit *c; + const char *shortmsg; + + git_buf_clear(buf); + + if (git_commit_lookup(&c, repo, id) < 0) + return -1; + + shortmsg = git_commit_summary(c); + git_buf_printf(buf, "commit%s: %s", + git_commit_parentcount(c) == 0 ? " (initial)" : "", + shortmsg); + git_commit_free(c); + + return 0; +} + int git_commit_create_from_callback( git_oid *id, git_repository *repo, @@ -81,19 +101,11 @@ int git_commit_create_from_callback( if (update_ref != NULL) { int error; - git_commit *c; - const char *shortmsg; git_buf reflog_msg = GIT_BUF_INIT; - if (git_commit_lookup(&c, repo, id) < 0) + if ((error = commit_reflog_message(&reflog_msg, repo, id)) < 0) goto on_error; - shortmsg = git_commit_summary(c); - git_buf_printf(&reflog_msg, "commit%s: %s", - git_commit_parentcount(c) == 0 ? " (initial)" : "", - shortmsg); - git_commit_free(c); - error = git_reference__update_terminal(repo, update_ref, id, committer, git_buf_cstr(&reflog_msg)); @@ -273,6 +285,48 @@ int git_commit_amend( &tree_id, commit_parent_for_amend, (void *)commit_to_amend); } +int git_commit_append( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree) +{ + git_buf reflog_msg = GIT_BUF_INIT; + git_reference *ref, *ref2; + const git_oid *parent_id = NULL; + git_commit *parent; + int error; + + assert(repo && update_ref && author && committer && message); + + if ((error = git_reference_lookup_resolved(&ref, repo, update_ref, 5)) < 0) + return error; + + parent_id = git_reference_target(ref); + if ((error = git_commit_lookup(&parent, repo, parent_id)) < 0) + goto out; + + error = git_commit_create_v(id, repo, NULL, author, committer, message_encoding, message, tree, 1, parent_id); + if (error < 0) + goto out; + + if ((error = commit_reflog_message(&reflog_msg, repo, parent_id)) < 0) + goto out; + + error = git_reference_set_target(&ref2, ref, id, committer, git_buf_cstr(&reflog_msg)); + git_buf_free(&reflog_msg); + +out: + git_commit_free(parent); + git_reference_free(ref); + git_reference_free(ref2); + return error; +} + int git_commit__parse(void *_commit, git_odb_object *odb_obj) { git_commit *commit = _commit; diff --git a/tests/commit/write.c b/tests/commit/write.c index b1cdf4485..84cc99133 100644 --- a/tests/commit/write.c +++ b/tests/commit/write.c @@ -158,3 +158,30 @@ void test_commit_write__root(void) git_signature_free(committer); git_reflog_free(log); } + +void test_commit_write__append(void) +{ + git_tree *tree; + git_oid tree_id, commit_id; + git_signature *author, *committer; + + git_oid_fromstr(&tree_id, tree_oid); + cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); + + cl_git_pass(git_signature_new(&author, committer_name, committer_email, 987654321, 90)); + cl_git_pass(git_signature_new(&committer, committer_name, committer_email, 123456789, 60)); + + cl_git_pass(git_commit_append( + &commit_id, /* out id */ + g_repo, + "HEAD", + author, + committer, + NULL, + root_commit_message, + tree)); + + git_tree_free(tree); + git_signature_free(committer); + git_signature_free(author); +} |