From 64c2a9d5fdd51c1c7046697b0e47ee1808f498e3 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Fri, 19 Sep 2014 22:02:53 +0100 Subject: [PATCH] Masterlist update can now roll back branch tip. When the remote branch is older than the local branch, the local branch tip (ie. HEAD) will be updated to point to the same commit as the remote branch. Fixes #297. --- src/backend/git.cpp | 56 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/backend/git.cpp b/src/backend/git.cpp index 28ec18a4..b35f27e0 100644 --- a/src/backend/git.cpp +++ b/src/backend/git.cpp @@ -42,7 +42,20 @@ namespace lc = boost::locale; namespace loot { struct git_handler { public: - git_handler() : repo(nullptr), remote(nullptr), cfg(nullptr), obj(nullptr), commit(nullptr), ref(nullptr), ref2(nullptr), sig(nullptr), blob(nullptr), merge_head(nullptr), tree(nullptr), diff(nullptr), buf({ 0 }) {} + git_handler() : + repo(nullptr), + remote(nullptr), + cfg(nullptr), + obj(nullptr), + commit(nullptr), + ref(nullptr), + ref2(nullptr), + sig(nullptr), + blob(nullptr), + merge_head(nullptr), + tree(nullptr), + diff(nullptr), + buf({0}) {} ~git_handler() { git_commit_free(commit); @@ -183,7 +196,7 @@ namespace loot { git.call(git_signature_new(&git.sig, "LOOT", "loot@placeholder.net", 0, 0)); BOOST_LOG_TRIVIAL(debug) << "Setting up checkout options."; - char * paths[] ={ "masterlist.yaml" }; + char * paths[] = {"masterlist.yaml"}; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; checkout_opts.paths.strings = paths; @@ -352,13 +365,44 @@ namespace loot { git.ref2 = nullptr; } else if ((analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) != 0) { + // No merge is required, but HEAD might be ahead of the remote branch. Check + // to see if that's the case, and move HEAD back to match the remote branch + // if so. Otherwise, exit early to skip unnecessary masterlist parsing. // No update necessary, so exit early to skip unnecessary masterlist parsing. BOOST_LOG_TRIVIAL(trace) << "Local branch is up-to-date with remote branch."; - BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD."; - git.call(git_checkout_head(git.repo, &checkout_opts)); + BOOST_LOG_TRIVIAL(trace) << "Checking to see if local and remote branch heads are equal."; + // Get the local branch and remote branch head commit IDs. - return false; + // Local branch. + git.call(git_reference_peel(&git.obj, git.ref, GIT_OBJ_COMMIT)); + const git_oid * local_commit_id = git_object_id(git.obj); + git_object_free(git.obj); + git.obj = nullptr; + + // Remote branch. + git.call(git_reference_peel(&git.obj, git.ref2, GIT_OBJ_COMMIT)); + const git_oid * remote_commit_id = git_object_id(git.obj); + git_reference_free(git.ref2); + git.ref2 = nullptr; + git_object_free(git.obj); + git.obj = nullptr; + + if (local_commit_id->id != remote_commit_id->id) { + BOOST_LOG_TRIVIAL(trace) << "Branch heads are not equal, updating local HEAD."; + // Commit IDs don't match, update HEAD, and continue with normal update procedure. + git.call(git_reference_set_target(&git.ref2, git.ref, remote_commit_id, git.sig, "Setting branch reference.")); + git_reference_free(git.ref2); + git.ref2 = nullptr; + } + else { + // Commit IDs match, just checkout HEAD then exit early. + BOOST_LOG_TRIVIAL(trace) << "Branch heads are equal."; + BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD."; + git.call(git_checkout_head(git.repo, &checkout_opts)); + + return false; + } } else { // The local repository can't be easily merged. It's best just to delete and re-clone it. @@ -414,7 +458,7 @@ namespace loot { git.ref = nullptr; git.obj = nullptr; git.commit = nullptr; - git.buf ={ 0 }; + git.buf = {0}; //Now try parsing the masterlist. BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing.";