commit - 2f51b5b3dbc9fb8bc58001a3e80bf7b2cdf8c6a2
commit + de18fc635cbce498d8f11d0b994a9de1821760bb
blob - f48a524c2e941f59e208fe7590e665f47e95256a
blob + a39387abda91c220d8e14e5faab47e21bc1396f4
--- got/got.c
+++ got/got.c
if (error)
goto done;
- error = got_worktree_commit(&id, worktree, path, logmsg, repo);
+ error = got_worktree_commit(&id, worktree, path,
+ "Stefan Sperling <stsp@stsp.name>", NULL, logmsg, repo);
if (error)
goto done;
blob - debcb302f5ffcd4e16b249bb81b570b59be23923
blob + 27d9c4b14fdad4299d1cdd8a2cf811e17f143565
--- include/got_worktree.h
+++ include/got_worktree.h
* The worktree's base commit will be set to this new commit.
* Files unaffected by this commit operation will retain their
* current base commit.
- * A non-empty log message must be specified.
+ * An author and a non-empty log message must be specified.
+ * The name of the committer is optional (may be NULL).
* If an on-disk path is specified, only commit changes at or within this path.
*/
-const struct got_error *
-got_worktree_commit(struct got_object_id **,
- struct got_worktree *, const char *, const char *,
- struct got_repository *);
+const struct got_error *got_worktree_commit(struct got_object_id **,
+ struct got_worktree *, const char *, const char *, const char *,
+ const char *, struct got_repository *);
blob - 4d0047944714aaef7dbd3063372dcb83d7f2bffe
blob + 011e79e1b6f5f62d4fdb6d0658db9c490498352a
--- lib/got_lib_object_create.h
+++ lib/got_lib_object_create.h
const char *, struct got_repository *);
const struct got_error *got_object_tree_create(struct got_object_id **,
struct got_tree_entries *, struct got_repository *);
+const struct got_error *got_object_commit_create(struct got_object_id **,
+ struct got_object_id *, struct got_object_id_queue *, int,
+ const char *, time_t, const char *, time_t, const char *,
+ struct got_repository *);
blob - 8c94148d642736807ad761ea0d23f5284eeee348
blob + 6e0d38934875115a92f1d9ea9e6ce822976910f7
--- lib/object_create.c
+++ lib/object_create.c
done:
free(header);
if (treefile && fclose(treefile) != 0 && err == NULL)
+ err = got_error_from_errno();
+ if (err) {
+ free(*id);
+ *id = NULL;
+ }
+ return err;
+}
+
+const struct got_error *
+got_object_commit_create(struct got_object_id **id,
+ struct got_object_id *tree_id, struct got_object_id_queue *parent_ids,
+ int nparents, const char *author, time_t author_time,
+ const char *committer, time_t committer_time,
+ const char *logmsg, struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ SHA1_CTX sha1_ctx;
+ char *header = NULL, *tree_str = NULL;
+ char *author_str = NULL, *committer_str = NULL;
+ char *id_str = NULL;
+ size_t headerlen, len = 0, n;
+ FILE *commitfile = NULL;
+ struct got_object_qid *qid;
+
+ *id = NULL;
+
+ SHA1Init(&sha1_ctx);
+
+ if (asprintf(&author_str, "%s%s %lld +0000\n",
+ GOT_COMMIT_LABEL_AUTHOR, author, author_time) == -1)
+ return got_error_from_errno();
+
+ if (asprintf(&committer_str, "%s%s %lld +0000\n",
+ GOT_COMMIT_LABEL_COMMITTER, committer ? committer : author,
+ committer ? committer_time : author_time)
+ == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ len = strlen(GOT_COMMIT_LABEL_TREE) + SHA1_DIGEST_STRING_LENGTH +
+ nparents *
+ (strlen(GOT_COMMIT_LABEL_PARENT) + SHA1_DIGEST_STRING_LENGTH) +
+ + strlen(author_str) + strlen(committer_str) + 2 + strlen(logmsg);
+
+ if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_COMMIT, len) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ headerlen = strlen(header) + 1;
+ SHA1Update(&sha1_ctx, header, headerlen);
+
+ commitfile = got_opentemp();
+ if (commitfile == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ n = fwrite(header, 1, headerlen, commitfile);
+ if (n != headerlen) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ err = got_object_id_str(&id_str, tree_id);
+ if (err)
+ goto done;
+ if (asprintf(&tree_str, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str)
+ == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ len = strlen(tree_str);
+ SHA1Update(&sha1_ctx, tree_str, len);
+ n = fwrite(tree_str, 1, len, commitfile);
+ if (n != len) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ SIMPLEQ_FOREACH(qid, parent_ids, entry) {
+ char *parent_str = NULL;
+
+ free(id_str);
+
+ err = got_object_id_str(&id_str, qid->id);
+ if (err)
+ goto done;
+ if (asprintf(&parent_str, "%s%s\n", GOT_COMMIT_LABEL_PARENT,
+ id_str) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ len = strlen(parent_str);
+ SHA1Update(&sha1_ctx, parent_str, len);
+ n = fwrite(parent_str, 1, len, commitfile);
+ if (n != len) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ free(parent_str);
+ goto done;
+ }
+ free(parent_str);
+ }
+
+ len = strlen(author_str);
+ SHA1Update(&sha1_ctx, author_str, len);
+ n = fwrite(author_str, 1, len, commitfile);
+ if (n != len) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ len = strlen(committer_str);
+ SHA1Update(&sha1_ctx, committer_str, len);
+ n = fwrite(committer_str, 1, len, commitfile);
+ if (n != len) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ SHA1Update(&sha1_ctx, "\n", 1);
+ n = fwrite("\n", 1, 1, commitfile);
+ if (n != 1) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ len = strlen(logmsg);
+ SHA1Update(&sha1_ctx, logmsg, len);
+ n = fwrite(logmsg, 1, len, commitfile);
+ if (n != len) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ SHA1Update(&sha1_ctx, "\n", 1);
+ n = fwrite("\n", 1, 1, commitfile);
+ if (n != 1) {
+ err = got_ferror(commitfile, GOT_ERR_IO);
+ goto done;
+ }
+
+ *id = malloc(sizeof(**id));
+ if (*id == NULL) {
err = got_error_from_errno();
+ goto done;
+ }
+ SHA1Final((*id)->sha1, &sha1_ctx);
+
+ if (fflush(commitfile) != 0) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ rewind(commitfile);
+
+ err = create_object_file(*id, commitfile, repo);
+done:
+ free(header);
+ free(tree_str);
+ free(author_str);
+ free(committer_str);
+ if (commitfile && fclose(commitfile) != 0 && err == NULL)
+ err = got_error_from_errno();
if (err) {
free(*id);
*id = NULL;
blob - 90a97466396a51ba49e87eb6064fcc811bfb0ddc
blob + 1bd890d5772e107b2e3a9ed899572810e276677d
--- lib/worktree.c
+++ lib/worktree.c
const struct got_error *
got_worktree_commit(struct got_object_id **new_commit_id,
struct got_worktree *worktree, const char *ondisk_path,
+ const char *author, const char *committer,
const char *logmsg, struct got_repository *repo)
{
const struct got_error *err = NULL, *unlockerr = NULL;
struct got_commit_object *base_commit = NULL;
struct got_tree_object *base_tree = NULL;
struct got_object_id *new_tree_id = NULL;
+ struct got_object_id_queue parent_ids;
+ struct got_object_qid *pid = NULL;
*new_commit_id = NULL;
TAILQ_INIT(&commitable_paths);
+ SIMPLEQ_INIT(&parent_ids);
if (ondisk_path) {
err = got_path_skip_common_ancestor(&relpath,
if (err)
goto done;
+ /* TODO: out-of-dateness check */
+
/* TODO: collect commit message if not specified */
/* Create blobs from added and modified files and record their IDs. */
if (err)
goto done;
- /* TODO: Write new commit. */
-
+ err = got_object_qid_alloc(&pid, worktree->base_commit_id);
+ if (err)
+ goto done;
+ SIMPLEQ_INSERT_TAIL(&parent_ids, pid, entry);
+ err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids,
+ 1, author, time(NULL), committer, time(NULL), logmsg, repo);
+ got_object_qid_free(pid);
done:
unlockerr = lock_worktree(worktree, LOCK_SH);
if (unlockerr && err == NULL)