summaryrefslogtreecommitdiffstats
path: root/save-git.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2014-03-13 15:42:45 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2014-03-13 20:48:31 -0700
commit3fe0019bc2939aea4e89cbb8bc5aeb5edeb456d9 (patch)
treecbd3b2b6fa7f2b31977256f1e909920ebe916840 /save-git.c
parent0b114a198eb3a648c507bc801a0343bf04dc0191 (diff)
downloadsubsurface-3fe0019bc2939aea4e89cbb8bc5aeb5edeb456d9.tar.gz
git object format: make sure parenthood isn't lost when saving
This makes subsurface remember the git source commit of the dive data. If you save to an existing branch, subsurface will now complain and refuse to save if you try to save if the existing branch is not related to the original source. That would destroy the history of the dive data, which in turn would make it impossible to do sane merging of the data. If you save to a new branch, it will see if the previous parent commit is known in the repository you are saving to, and will save parenthood information if so. Otherwise it will save it as a new parentless commit ("root commit" in git parlance). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'save-git.c')
-rw-r--r--save-git.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/save-git.c b/save-git.c
index 4760fe32a..ab00ba951 100644
--- a/save-git.c
+++ b/save-git.c
@@ -741,6 +741,23 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o
}
/*
+ * See if we can find the parent ID that the git data came from
+ */
+static git_object *try_to_find_parent(const char *hex_id, git_repository *repo)
+{
+ git_oid object_id;
+ git_commit *commit;
+
+ if (!hex_id)
+ return NULL;
+ if (git_oid_fromstr(&object_id, hex_id))
+ return NULL;
+ if (git_commit_lookup(&commit, repo, &object_id))
+ return NULL;
+ return (git_object *)commit;
+}
+
+/*
* libgit2 revision 0.20 and earlier do not have the signature and
* message log arguments.
*/
@@ -769,15 +786,18 @@ static int create_new_commit(git_repository *repo, const char *branch, git_oid *
case GIT_EINVALIDSPEC:
return report_error("Invalid branch name '%s'", branch);
case GIT_ENOTFOUND: /* We'll happily create it */
- ref = NULL; parent = NULL;
+ ref = NULL;
+ parent = try_to_find_parent(saved_git_id, repo);
break;
case 0:
if (git_reference_peel(&parent, ref, GIT_OBJ_COMMIT))
return report_error("Unable to look up parent in branch '%s'", branch);
- /* If the parent commit has the same tree ID, do nothing */
- if (git_oid_equal(tree_id, git_commit_tree_id((const git_commit *) parent)))
- return 0;
+ if (saved_git_id) {
+ const git_oid *id = git_commit_id((const git_commit *) parent);
+ if (git_oid_strcmp(id, saved_git_id))
+ return report_error("The git branch does not match the git parent of the source");
+ }
/* all good */
break;
@@ -790,12 +810,21 @@ static int create_new_commit(git_repository *repo, const char *branch, git_oid *
if (git_signature_now(&author, "Subsurface", "subsurface@hohndel.org"))
return report_error("No user name configuration in git repo");
- put_format(&commit_msg, "Created by subsurface %s\n", VERSION_STRING);
- if (git_commit_create_v(&commit_id, repo, NULL, author, author, NULL, mb_cstring(&commit_msg), tree, parent != NULL, parent))
- return report_error("Git commit create failed (%s)", strerror(errno));
-
- if (git_commit_lookup(&commit, repo, &commit_id))
- return report_error("Could not look up newly created commit");
+ /* If the parent commit has the same tree ID, do not create a new commit */
+ if (parent && git_oid_equal(tree_id, git_commit_tree_id((const git_commit *) parent))) {
+ /* If the parent already came from the ref, the commit is already there */
+ if (ref)
+ return 0;
+ /* Else we do want to create the new branch, but with the old commit */
+ commit = (git_commit *) parent;
+ } else {
+ put_format(&commit_msg, "Created by subsurface %s\n", VERSION_STRING);
+ if (git_commit_create_v(&commit_id, repo, NULL, author, author, NULL, mb_cstring(&commit_msg), tree, parent != NULL, parent))
+ return report_error("Git commit create failed (%s)", strerror(errno));
+
+ if (git_commit_lookup(&commit, repo, &commit_id))
+ return report_error("Could not look up newly created commit");
+ }
if (!ref) {
if (git_branch_create(&ref, repo, branch, commit, 0, author, "Create branch"))
@@ -803,6 +832,7 @@ static int create_new_commit(git_repository *repo, const char *branch, git_oid *
}
if (git_reference_set_target(&ref, ref, &commit_id, author, "Subsurface save event"))
return report_error("Failed to update branch '%s'", branch);
+ set_git_id(&commit_id);
return 0;
}
@@ -850,8 +880,7 @@ static int do_git_save(git_repository *repo, const char *branch, bool select_onl
return report_error("git tree write failed");
/* And save the tree! */
- create_new_commit(repo, branch, &id);
- return 0;
+ return create_new_commit(repo, branch, &id);
}
/*