Skip to content

Commit 9bbc8f3

Browse files
committed
Merge pull request libgit2#2962 from libgit2/cmn/reflog-annotated
Add annotated versions of ref-modying functions
2 parents 7800048 + 8acf058 commit 9bbc8f3

File tree

14 files changed

+247
-27
lines changed

14 files changed

+247
-27
lines changed

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ v0.22 + 1
1818
* The local transport now auto-scales the number of threads to use
1919
when creating the packfile instead of sticking to one.
2020

21+
* Reference renaming now uses the right id for the old value.
22+
23+
* The annotated version of branch creation, HEAD detaching and reset
24+
allow for specifying the expression from the user to be put into the
25+
reflog.
26+
2127
### API additions
2228

2329
* Parsing and retrieving a configuration value as a path is exposed
@@ -33,7 +39,14 @@ v0.22 + 1
3339
* `git_config_get_string_buf()` provides a way to safely retrieve a
3440
string from a non-snapshot configuration.
3541

36-
* Reference renaming now uses the right id for the old value.
42+
* `git_annotated_commit_from_revspec()` allows to get an annotated
43+
commit from an extended sha synatx string.
44+
45+
* `git_repository_set_head_detached_from_annotated()`,
46+
`git_branch_create_from_annotated()` and
47+
`git_reset_from_annotated()` allow for the caller to provide an
48+
annotated commit through which they can control what expression is
49+
put into the reflog as the source/target.
3750

3851
* `git_index_add_frombuffer()` can now create a blob from memory
3952
buffer and add it to the index which is attached to a repository.

include/git2/annotated_commit.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,23 @@ GIT_EXTERN(int) git_annotated_commit_lookup(
7777
git_repository *repo,
7878
const git_oid *id);
7979

80+
/**
81+
* Creates a `git_annotated_comit` from a revision string.
82+
*
83+
* See `man gitrevisions`, or
84+
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for
85+
* information on the syntax accepted.
86+
*
87+
* @param out pointer to store the git_annotated_commit result in
88+
* @param repo repository that contains the given commit
89+
* @param revspec the extended sha syntax string to use to lookup the commit
90+
* @return 0 on success or error code
91+
*/
92+
GIT_EXTERN(int) git_annotated_commit_from_revspec(
93+
git_annotated_commit **out,
94+
git_repository *repo,
95+
const char *revspec);
96+
8097
/**
8198
* Gets the commit ID that the given `git_annotated_commit` refers to.
8299
*

include/git2/branch.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ GIT_EXTERN(int) git_branch_create(
5454
const git_commit *target,
5555
int force);
5656

57+
/**
58+
* Create a new branch pointing at a target commit
59+
*
60+
* This behaves like `git_branch_create()` but takes an annotated
61+
* commit, which lets you specify which extended sha syntax string was
62+
* specified by a user, allowing for more exact reflog messages.
63+
*
64+
* See the documentation for `git_branch_create()`.
65+
*
66+
* @see git_branch_create
67+
*/
68+
GIT_EXTERN(int) git_branch_create_from_annotated(
69+
git_reference **ref_out,
70+
git_repository *repository,
71+
const char *branch_name,
72+
const git_annotated_commit *commit,
73+
int force);
74+
5775
/**
5876
* Delete an existing branch reference.
5977
*

include/git2/repository.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,22 @@ GIT_EXTERN(int) git_repository_set_head_detached(
629629
git_repository* repo,
630630
const git_oid* commitish);
631631

632+
/**
633+
* Make the repository HEAD directly point to the Commit.
634+
*
635+
* This behaves like `git_repository_set_head_detached()` but takes an
636+
* annotated commit, which lets you specify which extended sha syntax
637+
* string was specified by a user, allowing for more exact reflog
638+
* messages.
639+
*
640+
* See the documentation for `git_repository_set_head_detached()`.
641+
*
642+
* @see git_repository_set_head_detached
643+
*/
644+
GIT_EXTERN(int) git_repository_set_head_detached_from_annotated(
645+
git_repository *repo,
646+
const git_annotated_commit *commitish);
647+
632648
/**
633649
* Detach the HEAD.
634650
*

include/git2/reset.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ GIT_EXTERN(int) git_reset(
6464
git_reset_t reset_type,
6565
git_checkout_options *checkout_opts);
6666

67+
/**
68+
* Sets the current head to the specified commit oid and optionally
69+
* resets the index and working tree to match.
70+
*
71+
* This behaves like `git_reset()` but takes an annotated commit,
72+
* which lets you specify which extended sha syntax string was
73+
* specified by a user, allowing for more exact reflog messages.
74+
*
75+
* See the documentation for `git_reset()`.
76+
*
77+
* @see git_reset
78+
*/
79+
GIT_EXTERN(int) git_reset_from_annotated(
80+
git_repository *repo,
81+
git_annotated_commit *commit,
82+
git_reset_t reset_type,
83+
git_checkout_options *checkout_opts);
84+
6785
/**
6886
* Updates some entries in the index from the target commit tree.
6987
*

src/annotated_commit.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "git2/refs.h"
1313
#include "git2/repository.h"
1414
#include "git2/annotated_commit.h"
15+
#include "git2/revparse.h"
1516

1617
static int annotated_commit_init(
1718
git_annotated_commit **out,
@@ -96,6 +97,33 @@ int git_annotated_commit_from_fetchhead(
9697
return annotated_commit_init(out, repo, id, branch_name, remote_url);
9798
}
9899

100+
int git_annotated_commit_from_revspec(
101+
git_annotated_commit **out,
102+
git_repository *repo,
103+
const char *revspec)
104+
{
105+
git_object *obj, *commit;
106+
int error;
107+
108+
assert(out && repo && revspec);
109+
110+
if ((error = git_revparse_single(&obj, repo, revspec)) < 0)
111+
return error;
112+
113+
if ((error = git_object_peel(&commit, obj, GIT_OBJ_COMMIT))) {
114+
git_object_free(obj);
115+
return error;
116+
}
117+
118+
error = annotated_commit_init(out, repo, git_object_id(commit), revspec, NULL);
119+
120+
git_object_free(obj);
121+
git_object_free(commit);
122+
123+
return error;
124+
}
125+
126+
99127
const git_oid *git_annotated_commit_id(
100128
const git_annotated_commit *annotated_commit)
101129
{

src/branch.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "refspec.h"
1313
#include "refs.h"
1414
#include "remote.h"
15+
#include "annotated_commit.h"
1516

1617
#include "git2/branch.h"
1718

@@ -49,11 +50,12 @@ static int not_a_local_branch(const char *reference_name)
4950
return -1;
5051
}
5152

52-
int git_branch_create(
53+
static int create_branch(
5354
git_reference **ref_out,
5455
git_repository *repository,
5556
const char *branch_name,
5657
const git_commit *commit,
58+
const char *from,
5759
int force)
5860
{
5961
int is_head = 0;
@@ -86,7 +88,7 @@ int git_branch_create(
8688
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
8789
goto cleanup;
8890

89-
if (git_buf_printf(&log_message, "branch: Created from %s", git_oid_tostr_s(git_commit_id(commit))) < 0)
91+
if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0)
9092
goto cleanup;
9193

9294
error = git_reference_create(&branch, repository,
@@ -102,6 +104,26 @@ int git_branch_create(
102104
return error;
103105
}
104106

107+
int git_branch_create(
108+
git_reference **ref_out,
109+
git_repository *repository,
110+
const char *branch_name,
111+
const git_commit *commit,
112+
int force)
113+
{
114+
return create_branch(ref_out, repository, branch_name, commit, git_oid_tostr_s(git_commit_id(commit)), force);
115+
}
116+
117+
int git_branch_create_from_annotated(
118+
git_reference **ref_out,
119+
git_repository *repository,
120+
const char *branch_name,
121+
const git_annotated_commit *commit,
122+
int force)
123+
{
124+
return create_branch(ref_out, repository, branch_name, commit->commit, commit->ref_name, force);
125+
}
126+
105127
int git_branch_delete(git_reference *branch)
106128
{
107129
int is_head;

src/repository.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "remote.h"
2727
#include "merge.h"
2828
#include "diff_driver.h"
29+
#include "annotated_commit.h"
2930

3031
#ifdef GIT_WIN32
3132
# include "win32/w32_util.h"
@@ -1961,27 +1962,28 @@ int git_repository_set_head(
19611962
return error;
19621963
}
19631964

1964-
int git_repository_set_head_detached(
1965-
git_repository* repo,
1966-
const git_oid* commitish)
1965+
static int detach(git_repository *repo, const git_oid *id, const char *from)
19671966
{
19681967
int error;
19691968
git_buf log_message = GIT_BUF_INIT;
19701969
git_object *object = NULL, *peeled = NULL;
19711970
git_reference *new_head = NULL, *current = NULL;
19721971

1973-
assert(repo && commitish);
1972+
assert(repo && id);
19741973

19751974
if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
19761975
return error;
19771976

1978-
if ((error = git_object_lookup(&object, repo, commitish, GIT_OBJ_ANY)) < 0)
1977+
if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
19791978
goto cleanup;
19801979

19811980
if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
19821981
goto cleanup;
19831982

1984-
if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(peeled)))) < 0)
1983+
if (from == NULL)
1984+
from = git_oid_tostr_s(git_object_id(peeled));
1985+
1986+
if ((error = checkout_message(&log_message, current, from)) < 0)
19851987
goto cleanup;
19861988

19871989
error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
@@ -1995,6 +1997,22 @@ int git_repository_set_head_detached(
19951997
return error;
19961998
}
19971999

2000+
int git_repository_set_head_detached(
2001+
git_repository* repo,
2002+
const git_oid* commitish)
2003+
{
2004+
return detach(repo, commitish, NULL);
2005+
}
2006+
2007+
int git_repository_set_head_detached_from_annotated(
2008+
git_repository *repo,
2009+
const git_annotated_commit *commitish)
2010+
{
2011+
assert(repo && commitish);
2012+
2013+
return detach(repo, git_annotated_commit_id(commitish), commitish->ref_name);
2014+
}
2015+
19982016
int git_repository_detach_head(git_repository* repo)
19992017
{
20002018
git_reference *old_head = NULL, *new_head = NULL, *current = NULL;

src/reset.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "tag.h"
1111
#include "merge.h"
1212
#include "diff.h"
13+
#include "annotated_commit.h"
1314
#include "git2/reset.h"
1415
#include "git2/checkout.h"
1516
#include "git2/merge.h"
@@ -96,9 +97,10 @@ int git_reset_default(
9697
return error;
9798
}
9899

99-
int git_reset(
100+
static int reset(
100101
git_repository *repo,
101102
git_object *target,
103+
const char *to,
102104
git_reset_t reset_type,
103105
git_checkout_options *checkout_opts)
104106
{
@@ -139,7 +141,7 @@ int git_reset(
139141
goto cleanup;
140142
}
141143

142-
if ((error = git_buf_printf(&log_message, "reset: moving to %s", git_oid_tostr_s(git_object_id(commit)))) < 0)
144+
if ((error = git_buf_printf(&log_message, "reset: moving to %s", to)) < 0)
143145
return error;
144146

145147
/* move HEAD to the new target */
@@ -176,3 +178,21 @@ int git_reset(
176178

177179
return error;
178180
}
181+
182+
int git_reset(
183+
git_repository *repo,
184+
git_object *target,
185+
git_reset_t reset_type,
186+
git_checkout_options *checkout_opts)
187+
{
188+
return reset(repo, target, git_oid_tostr_s(git_object_id(target)), reset_type, checkout_opts);
189+
}
190+
191+
int git_reset_from_annotated(
192+
git_repository *repo,
193+
git_annotated_commit *commit,
194+
git_reset_t reset_type,
195+
git_checkout_options *checkout_opts)
196+
{
197+
return reset(repo, (git_object *) commit->commit, commit->ref_name, reset_type, checkout_opts);
198+
}

tests/refs/branches/create.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ void test_refs_branches_create__default_reflog_message(void)
9797
git_reflog *log;
9898
git_buf buf = GIT_BUF_INIT;
9999
const git_reflog_entry *entry;
100+
git_annotated_commit *annotated;
100101
git_signature *sig;
101102
git_config *cfg;
102103

@@ -116,6 +117,21 @@ void test_refs_branches_create__default_reflog_message(void)
116117
cl_assert_equal_s(git_buf_cstr(&buf), git_reflog_entry_message(entry));
117118
cl_assert_equal_s(sig->email, git_reflog_entry_committer(entry)->email);
118119

120+
cl_git_pass(git_reference_remove(repo, "refs/heads/" NEW_BRANCH_NAME));
121+
git_reference_free(branch);
122+
git_reflog_free(log);
123+
git_buf_clear(&buf);
124+
125+
cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "e90810b8df3"));
126+
cl_git_pass(git_branch_create_from_annotated(&branch, repo, NEW_BRANCH_NAME, annotated, true));
127+
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/" NEW_BRANCH_NAME));
128+
129+
entry = git_reflog_entry_byindex(log, 0);
130+
cl_git_pass(git_buf_printf(&buf, "branch: Created from e90810b8df3"));
131+
cl_assert_equal_s(git_buf_cstr(&buf), git_reflog_entry_message(entry));
132+
cl_assert_equal_s(sig->email, git_reflog_entry_committer(entry)->email);
133+
134+
git_annotated_commit_free(annotated);
119135
git_buf_free(&buf);
120136
git_reflog_free(log);
121137
git_signature_free(sig);

0 commit comments

Comments
 (0)