mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-21 22:16:24 +00:00
commit: introduce git_commit_amend_from_...
Similar to the `git_commit_create_from_...` APIs, a simple amend function that uses smart defaults and amends HEAD from the staged changes or a given tree.
This commit is contained in:
@@ -612,6 +612,39 @@ GIT_EXTERN(int) git_commit_create_from_tree(
|
||||
const char *message,
|
||||
const git_commit_create_options *opts);
|
||||
|
||||
/**
|
||||
* Amends the HEAD commit in the repository using the staged changes;
|
||||
* this is a near analog to `git commit --amend -m message`.
|
||||
*
|
||||
* @param id pointer to store the new commit's object id
|
||||
* @param repo repository to commit changes in
|
||||
* @param message the commit message
|
||||
* @param opts options for creating the commit
|
||||
* @return 0 on success or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_amend_from_stage(
|
||||
git_oid *id,
|
||||
git_repository *repo,
|
||||
const char *message,
|
||||
const git_commit_create_options *opts);
|
||||
|
||||
/**
|
||||
* Amends the HEAD commit in the repository using the given tree.
|
||||
*
|
||||
* @param id pointer to store the new commit's object id
|
||||
* @param repo repository to commit changes in
|
||||
* @param tree tree to point the commit to
|
||||
* @param message the commit message
|
||||
* @param opts options for creating the commit
|
||||
* @return 0 on success or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_amend_from_tree(
|
||||
git_oid *id,
|
||||
git_repository *repo,
|
||||
const git_tree *tree,
|
||||
const char *message,
|
||||
const git_commit_create_options *opts);
|
||||
|
||||
/**
|
||||
* Amend an existing commit by replacing only non-NULL values.
|
||||
*
|
||||
|
||||
@@ -1330,6 +1330,100 @@ int git_commit_create_from_tree(
|
||||
return create_from_tree(out, repo, tree, message, &opts);
|
||||
}
|
||||
|
||||
int git_commit_amend_from_stage(
|
||||
git_oid *out,
|
||||
git_repository *repo,
|
||||
const char *message,
|
||||
const git_commit_create_options *opts)
|
||||
{
|
||||
git_index *index = NULL;
|
||||
git_oid tree_id;
|
||||
git_tree *tree = NULL;
|
||||
int error = 0;
|
||||
|
||||
GIT_ASSERT_ARG(out && repo);
|
||||
|
||||
if (git_repository_index(&index, repo) < 0 ||
|
||||
git_index_write_tree(&tree_id, index) < 0 ||
|
||||
git_tree_lookup(&tree, repo, &tree_id) < 0) {
|
||||
error = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
error = git_commit_amend_from_tree(out, repo, tree, message, opts);
|
||||
|
||||
done:
|
||||
git_tree_free(tree);
|
||||
git_index_free(index);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_amend_from_tree(
|
||||
git_oid *out,
|
||||
git_repository *repo,
|
||||
const git_tree *tree,
|
||||
const char *given_message,
|
||||
const git_commit_create_options *given_opts)
|
||||
{
|
||||
git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT;
|
||||
git_commit_create_ext_options ext_opts = GIT_COMMIT_CREATE_EXT_OPTIONS_INIT;
|
||||
git_reference *head_ref = NULL;
|
||||
git_commit *head_commit = NULL;
|
||||
git_signature *new_committer = NULL;
|
||||
const git_signature *author, *committer;
|
||||
const char *message;
|
||||
int error;
|
||||
|
||||
GIT_ASSERT_ARG(out && repo && tree);
|
||||
|
||||
if (given_opts)
|
||||
memcpy(&opts, given_opts, sizeof(git_commit_create_options));
|
||||
|
||||
if ((error = git_repository_head(&head_ref, repo)) < 0 ||
|
||||
(error = git_reference_peel((git_object **)&head_commit, head_ref, GIT_OBJECT_COMMIT)) < 0)
|
||||
goto done;
|
||||
|
||||
if (opts.author) {
|
||||
author = opts.author;
|
||||
} else {
|
||||
author = git_commit_author(head_commit);
|
||||
}
|
||||
|
||||
if (opts.committer) {
|
||||
committer = opts.committer;
|
||||
} else {
|
||||
if ((error = git_signature_default(&new_committer, repo)) < 0)
|
||||
goto done;
|
||||
|
||||
committer = new_committer;
|
||||
}
|
||||
|
||||
if (given_message) {
|
||||
message = given_message;
|
||||
ext_opts.message_encoding = opts.message_encoding;
|
||||
} else {
|
||||
message = git_commit_message(head_commit);
|
||||
ext_opts.message_encoding = git_commit_message_encoding(head_commit);
|
||||
}
|
||||
|
||||
error = git_commit__create_internal(
|
||||
out, repo, author, committer, message, git_tree_id(tree),
|
||||
commit_parent_for_amend, (void *)head_commit, &ext_opts,
|
||||
false);
|
||||
|
||||
if (!error)
|
||||
error = git_reference__update_for_commit(
|
||||
repo, head_ref, NULL, out, "commit");
|
||||
|
||||
done:
|
||||
git_signature_free(new_committer);
|
||||
git_commit_free(head_commit);
|
||||
git_reference_free(head_ref);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int git_commit_committer_with_mailmap(
|
||||
git_signature **out, const git_commit *commit, const git_mailmap *mailmap)
|
||||
{
|
||||
|
||||
122
tests/libgit2/commit/amend.c
Normal file
122
tests/libgit2/commit/amend.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "repository.h"
|
||||
|
||||
/* Fixture setup */
|
||||
static git_repository *g_repo;
|
||||
static git_signature *g_committer;
|
||||
|
||||
void test_commit_amend__initialize(void)
|
||||
{
|
||||
g_repo = cl_git_sandbox_init("testrepo2");
|
||||
cl_git_pass(git_signature_new(&g_committer, "libgit2 user", "nobody@noreply.libgit2.org", 987654321, 90));
|
||||
}
|
||||
|
||||
void test_commit_amend__cleanup(void)
|
||||
{
|
||||
git_signature_free(g_committer);
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
|
||||
void test_commit_amend__from_stage_simple(void)
|
||||
{
|
||||
git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT;
|
||||
git_index *index;
|
||||
git_oid commit_id;
|
||||
git_tree *tree;
|
||||
|
||||
opts.committer = g_committer;
|
||||
|
||||
cl_git_rewritefile("testrepo2/newfile.txt", "This is a new file.\n");
|
||||
cl_git_rewritefile("testrepo2/newfile2.txt", "This is a new file.\n");
|
||||
cl_git_rewritefile("testrepo2/README", "hello, world.\n");
|
||||
cl_git_rewritefile("testrepo2/new.txt", "hi there.\n");
|
||||
|
||||
cl_git_pass(git_repository_index(&index, g_repo));
|
||||
cl_git_pass(git_index_add_bypath(index, "newfile2.txt"));
|
||||
cl_git_pass(git_index_add_bypath(index, "README"));
|
||||
cl_git_pass(git_index_write(index));
|
||||
|
||||
cl_git_pass(git_commit_amend_from_stage(&commit_id, g_repo, NULL, &opts));
|
||||
|
||||
cl_git_pass(git_repository_head_tree(&tree, g_repo));
|
||||
|
||||
cl_assert_equal_oidstr("63ec0b083fd14c22a68fd2b1794f26e4b396b6b3", &commit_id);
|
||||
cl_assert_equal_oidstr("b27210772d0633870b4f486d04ed3eb5ebbef5e7", git_tree_id(tree));
|
||||
|
||||
git_index_free(index);
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
||||
void test_commit_amend__from_stage_newmessage(void)
|
||||
{
|
||||
git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT;
|
||||
git_oid commit_id;
|
||||
git_tree *tree;
|
||||
|
||||
opts.committer = g_committer;
|
||||
|
||||
cl_git_pass(git_commit_amend_from_stage(&commit_id, g_repo, "New message goes here.", &opts));
|
||||
|
||||
cl_git_pass(git_repository_head_tree(&tree, g_repo));
|
||||
|
||||
cl_assert_equal_oidstr("8b0e1cacc8380023705192466aaef8a15ddae7b3", &commit_id);
|
||||
cl_assert_equal_oidstr("c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", git_tree_id(tree));
|
||||
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
||||
void test_commit_amend__from_stage_nochanges(void)
|
||||
{
|
||||
git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT;
|
||||
git_oid commit_id;
|
||||
git_tree *tree;
|
||||
|
||||
opts.committer = g_committer;
|
||||
|
||||
cl_git_pass(git_commit_amend_from_stage(&commit_id, g_repo, NULL, &opts));
|
||||
|
||||
cl_git_pass(git_repository_head_tree(&tree, g_repo));
|
||||
|
||||
cl_assert_equal_oidstr("da86907c6d505a92c5683bece08f23d68ac785bd", &commit_id);
|
||||
cl_assert_equal_oidstr("c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", git_tree_id(tree));
|
||||
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
||||
void test_commit_amend__from_tree(void)
|
||||
{
|
||||
git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT;
|
||||
git_index *index;
|
||||
git_oid commit_id;
|
||||
git_oid tree_id;
|
||||
git_tree *tree, *lookedup;
|
||||
|
||||
opts.committer = g_committer;
|
||||
|
||||
cl_git_rewritefile("testrepo2/newfile.txt", "This is a new file.\n");
|
||||
cl_git_rewritefile("testrepo2/newfile2.txt", "This is a new file.\n");
|
||||
cl_git_rewritefile("testrepo2/README", "hello, world.\n");
|
||||
cl_git_rewritefile("testrepo2/new.txt", "hi there.\n");
|
||||
|
||||
cl_git_pass(git_repository_index(&index, g_repo));
|
||||
cl_git_pass(git_index_add_bypath(index, "newfile2.txt"));
|
||||
cl_git_pass(git_index_add_bypath(index, "README"));
|
||||
cl_git_pass(git_index_write(index));
|
||||
cl_git_pass(git_index_write_tree(&tree_id, index));
|
||||
|
||||
cl_assert_equal_oidstr("b27210772d0633870b4f486d04ed3eb5ebbef5e7", &tree_id);
|
||||
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
|
||||
|
||||
cl_git_pass(git_commit_amend_from_tree(&commit_id, g_repo, tree, NULL, &opts));
|
||||
|
||||
cl_git_pass(git_repository_head_tree(&lookedup, g_repo));
|
||||
|
||||
cl_assert_equal_oidstr("63ec0b083fd14c22a68fd2b1794f26e4b396b6b3", &commit_id);
|
||||
cl_assert_equal_oidstr("b27210772d0633870b4f486d04ed3eb5ebbef5e7", git_tree_id(lookedup));
|
||||
|
||||
git_index_free(index);
|
||||
git_tree_free(tree);
|
||||
git_tree_free(lookedup);
|
||||
}
|
||||
Reference in New Issue
Block a user