Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
534ca888
Commit
534ca888
authored
Mar 08, 2016
by
Edward Thomson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3652 from libgit2/cmn/commit-to-memory
commit: split creating the commit and writing it out
parents
eeff96c4
47cb42da
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
216 additions
and
47 deletions
+216
-47
CHANGELOG.md
+3
-0
include/git2/commit.h
+46
-0
src/commit.c
+128
-47
tests/commit/write.c
+39
-0
No files found.
CHANGELOG.md
View file @
534ca888
...
...
@@ -5,6 +5,9 @@ v0.24 + 1
### API additions
*
`git_commit_create_buffer()`
creates a commit and writes it into a
user-provided buffer instead of writing it into the object db.
### API removals
### Breaking API changes
...
...
include/git2/commit.h
View file @
534ca888
...
...
@@ -394,6 +394,52 @@ GIT_EXTERN(int) git_commit_amend(
const
char
*
message
,
const
git_tree
*
tree
);
/**
* Create a commit and write it into a buffer
*
* Create a commit as with `git_commit_create()` but instead of
* writing it to the objectdb, write the contents of the object into a
* buffer.
*
* @param out the buffer into which to write the commit object content
*
* @param repo Repository where the referenced tree and parents live
*
* @param author Signature with author and author time of commit
*
* @param committer Signature with committer and * commit time of commit
*
* @param message_encoding The encoding for the message in the
* commit, represented with a standard encoding name.
* E.g. "UTF-8". If NULL, no encoding header is written and
* UTF-8 is assumed.
*
* @param message Full message for this commit
*
* @param tree An instance of a `git_tree` object that will
* be used as the tree for the commit. This tree object must
* also be owned by the given `repo`.
*
* @param parent_count Number of parents for this commit
*
* @param parents Array of `parent_count` pointers to `git_commit`
* objects that will be used as the parents for this commit. This
* array may be NULL if `parent_count` is 0 (root commit). All the
* given commits must be owned by the `repo`.
*
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_commit_create_buffer
(
git_buf
*
out
,
git_repository
*
repo
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message
,
const
git_tree
*
tree
,
size_t
parent_count
,
const
git_commit
*
parents
[]);
/** @} */
GIT_END_DECL
#endif
src/commit.c
View file @
534ca888
...
...
@@ -18,6 +18,7 @@
#include "message.h"
#include "refs.h"
#include "object.h"
#include "oidarray.h"
void
git_commit__free
(
void
*
_commit
)
{
...
...
@@ -37,94 +38,143 @@ void git_commit__free(void *_commit)
git__free
(
commit
);
}
static
int
git_commit__create_internal
(
git_
oid
*
id
,
static
int
git_commit__create_
buffer_
internal
(
git_
buf
*
out
,
git_repository
*
repo
,
const
char
*
update_ref
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message
,
const
git_oid
*
tree
,
git_commit_parent_callback
parent_cb
,
void
*
parent_payload
,
bool
validate
)
git_array_oid_t
*
parents
)
{
git_reference
*
ref
=
NULL
;
int
error
=
0
,
matched_parent
=
0
;
const
git_oid
*
current_id
=
NULL
;
git_buf
commit
=
GIT_BUF_INIT
;
size_t
i
=
0
;
git_odb
*
odb
;
const
git_oid
*
parent
;
assert
(
id
&&
repo
&&
tree
&&
parent_cb
);
assert
(
out
&&
repo
&&
tree
);
if
(
validate
&&
!
git_object__is_valid
(
repo
,
tree
,
GIT_OBJ_TREE
))
return
-
1
;
git_oid__writebuf
(
out
,
"tree "
,
tree
);
if
(
update_ref
)
{
error
=
git_reference_lookup_resolved
(
&
ref
,
repo
,
update_ref
,
10
);
if
(
error
<
0
&&
error
!=
GIT_ENOTFOUND
)
return
error
;
for
(
i
=
0
;
i
<
git_array_size
(
*
parents
);
i
++
)
{
parent
=
git_array_get
(
*
parents
,
i
);
git_oid__writebuf
(
out
,
"parent "
,
parent
);
}
giterr_clear
();
if
(
ref
)
current_id
=
git_reference_target
(
ref
);
git_signature__writebuf
(
out
,
"author "
,
author
);
git_signature__writebuf
(
out
,
"committer "
,
committer
);
if
(
message_encoding
!=
NULL
)
git_buf_printf
(
out
,
"encoding %s
\n
"
,
message_encoding
);
git_buf_putc
(
out
,
'\n'
);
git_oid__writebuf
(
&
commit
,
"tree "
,
tree
);
if
(
git_buf_puts
(
out
,
message
)
<
0
)
goto
on_error
;
return
0
;
on_error:
git_buf_free
(
out
);
return
-
1
;
}
static
int
validate_tree_and_parents
(
git_array_oid_t
*
parents
,
git_repository
*
repo
,
const
git_oid
*
tree
,
git_commit_parent_callback
parent_cb
,
void
*
parent_payload
,
const
git_oid
*
current_id
,
bool
validate
)
{
size_t
i
;
int
error
;
git_oid
*
parent_cpy
;
const
git_oid
*
parent
;
if
(
validate
&&
!
git_object__is_valid
(
repo
,
tree
,
GIT_OBJ_TREE
))
return
-
1
;
i
=
0
;
while
((
parent
=
parent_cb
(
i
,
parent_payload
))
!=
NULL
)
{
if
(
validate
&&
!
git_object__is_valid
(
repo
,
parent
,
GIT_OBJ_COMMIT
))
{
error
=
-
1
;
goto
on_error
;
}
git_oid__writebuf
(
&
commit
,
"parent "
,
parent
);
if
(
i
==
0
&&
current_id
&&
git_oid_equal
(
current_id
,
parent
))
matched_parent
=
1
;
parent_cpy
=
git_array_alloc
(
*
parents
);
GITERR_CHECK_ALLOC
(
parent_cpy
);
git_oid_cpy
(
parent_cpy
,
parent
);
i
++
;
}
if
(
ref
&&
!
matched_parent
)
{
git_reference_free
(
ref
);
git_buf_free
(
&
commit
);
if
(
current_id
&&
git_oid_cmp
(
current_id
,
git_array_get
(
*
parents
,
0
)))
{
giterr_set
(
GITERR_OBJECT
,
"failed to create commit: current tip is not the first parent"
);
return
GIT_EMODIFIED
;
error
=
GIT_EMODIFIED
;
goto
on_error
;
}
git_signature__writebuf
(
&
commit
,
"author "
,
author
);
git_signature__writebuf
(
&
commit
,
"committer "
,
committer
);
return
0
;
if
(
message_encoding
!=
NULL
)
git_buf_printf
(
&
commit
,
"encoding %s
\n
"
,
message_encoding
);
on_error:
git_array_clear
(
*
parents
);
return
error
;
}
git_buf_putc
(
&
commit
,
'\n'
);
static
int
git_commit__create_internal
(
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_oid
*
tree
,
git_commit_parent_callback
parent_cb
,
void
*
parent_payload
,
bool
validate
)
{
int
error
;
git_odb
*
odb
;
git_reference
*
ref
=
NULL
;
git_buf
buf
=
GIT_BUF_INIT
;
const
git_oid
*
current_id
=
NULL
;
git_array_oid_t
parents
=
GIT_ARRAY_INIT
;
if
(
git_buf_puts
(
&
commit
,
message
)
<
0
)
goto
on_error
;
if
(
update_ref
)
{
error
=
git_reference_lookup_resolved
(
&
ref
,
repo
,
update_ref
,
10
);
if
(
error
<
0
&&
error
!=
GIT_ENOTFOUND
)
return
error
;
}
giterr_clear
();
if
(
ref
)
current_id
=
git_reference_target
(
ref
);
if
((
error
=
validate_tree_and_parents
(
&
parents
,
repo
,
tree
,
parent_cb
,
parent_payload
,
current_id
,
validate
))
<
0
)
goto
cleanup
;
error
=
git_commit__create_buffer_internal
(
&
buf
,
repo
,
author
,
committer
,
message_encoding
,
message
,
tree
,
&
parents
);
if
(
error
<
0
)
goto
cleanup
;
if
(
git_repository_odb__weakptr
(
&
odb
,
repo
)
<
0
)
goto
on_error
;
goto
cleanup
;
if
(
git_odb_write
(
id
,
odb
,
commit
.
ptr
,
commit
.
size
,
GIT_OBJ_COMMIT
)
<
0
)
goto
on_error
;
if
(
git_odb_write
(
id
,
odb
,
buf
.
ptr
,
buf
.
size
,
GIT_OBJ_COMMIT
)
<
0
)
goto
cleanup
;
git_buf_free
(
&
commit
);
if
(
update_ref
!=
NULL
)
{
error
=
git_reference__update_for_commit
(
repo
,
ref
,
update_ref
,
id
,
"commit"
);
git_reference_free
(
ref
);
return
error
;
goto
cleanup
;
}
return
0
;
on_error:
git_buf_free
(
&
commit
);
return
-
1
;
cleanup:
git_array_clear
(
parents
);
git_reference_free
(
ref
);
git_buf_free
(
&
buf
);
return
error
;
}
int
git_commit_create_from_callback
(
...
...
@@ -739,3 +789,34 @@ cleanup:
git_buf_clear
(
signed_data
);
return
error
;
}
int
git_commit_create_buffer
(
git_buf
*
out
,
git_repository
*
repo
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message
,
const
git_tree
*
tree
,
size_t
parent_count
,
const
git_commit
*
parents
[])
{
int
error
;
commit_parent_data
data
=
{
parent_count
,
parents
,
repo
};
git_array_oid_t
parents_arr
=
GIT_ARRAY_INIT
;
const
git_oid
*
tree_id
;
assert
(
tree
&&
git_tree_owner
(
tree
)
==
repo
);
tree_id
=
git_tree_id
(
tree
);
if
((
error
=
validate_tree_and_parents
(
&
parents_arr
,
repo
,
tree_id
,
commit_parent_from_array
,
&
data
,
NULL
,
true
))
<
0
)
return
error
;
error
=
git_commit__create_buffer_internal
(
out
,
repo
,
author
,
committer
,
message_encoding
,
message
,
tree_id
,
&
parents_arr
);
git_array_clear
(
parents_arr
);
return
error
;
}
tests/commit/write.c
View file @
534ca888
...
...
@@ -98,6 +98,45 @@ void test_commit_write__from_memory(void)
cl_assert_equal_s
(
commit_message
,
git_commit_message
(
commit
));
}
void
test_commit_write__into_buf
(
void
)
{
git_oid
tree_id
;
git_signature
*
author
,
*
committer
;
git_tree
*
tree
;
git_commit
*
parent
;
git_oid
parent_id
;
git_buf
commit
=
GIT_BUF_INIT
;
git_oid_fromstr
(
&
tree_id
,
tree_id_str
);
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
/* create signatures */
cl_git_pass
(
git_signature_new
(
&
committer
,
committer_name
,
committer_email
,
123456789
,
60
));
cl_git_pass
(
git_signature_new
(
&
author
,
committer_name
,
committer_email
,
987654321
,
90
));
git_oid_fromstr
(
&
parent_id
,
parent_id_str
);
cl_git_pass
(
git_commit_lookup
(
&
parent
,
g_repo
,
&
parent_id
));
cl_git_pass
(
git_commit_create_buffer
(
&
commit
,
g_repo
,
author
,
committer
,
NULL
,
root_commit_message
,
tree
,
1
,
(
const
git_commit
**
)
&
parent
));
cl_assert_equal_s
(
commit
.
ptr
,
"tree 1810dff58d8a660512d4832e740f692884338ccd
\n
\
parent 8496071c1b46c854b31185ea97743be6a8774479
\n
\
author Vicent Marti <vicent@github.com> 987654321 +0130
\n
\
committer Vicent Marti <vicent@github.com> 123456789 +0100
\n
\
\n
\
This is a root commit
\n
\
This is a root commit and should be the only one in this branch
\n
\
"
);
git_buf_free
(
&
commit
);
git_tree_free
(
tree
);
git_commit_free
(
parent
);
git_signature_free
(
author
);
git_signature_free
(
committer
);
}
// create a root commit
void
test_commit_write__root
(
void
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment