From c910d913d4d8aa0c69be33d587b49e59ac1cb8ef Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Sat, 5 Jul 2014 15:53:47 +0100 Subject: [PATCH] Implemented local branch merging during update. I'm sure I did this before, I must have discarded it by mistake... Also removed update retry, as there's some permissions issue that occurs with the repo packfiles whenever it is done. --- src/backend/network.cpp | 48 +++++++++++++++++++++++++++++++++++------ src/gui/main.cpp | 21 +++--------------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/backend/network.cpp b/src/backend/network.cpp index d08fb679..779c339f 100644 --- a/src/backend/network.cpp +++ b/src/backend/network.cpp @@ -43,7 +43,7 @@ namespace loot { struct git_handler { public: - git_handler() : repo(nullptr), remote(nullptr), cfg(nullptr), obj(nullptr), commit(nullptr), ref(nullptr), sig(nullptr), blob(nullptr) {} + git_handler() : repo(nullptr), remote(nullptr), cfg(nullptr), obj(nullptr), commit(nullptr), ref(nullptr), ref2(nullptr), sig(nullptr), blob(nullptr), merge_head(nullptr) {} ~git_handler() { git_commit_free(commit); @@ -52,8 +52,10 @@ namespace loot { git_remote_free(remote); git_repository_free(repo); git_reference_free(ref); + git_reference_free(ref2); git_signature_free(sig); git_blob_free(blob); + git_merge_head_free(merge_head); } void call(int error_code) { @@ -81,8 +83,11 @@ namespace loot { git_object * obj; git_commit * commit; git_reference * ref; + git_reference * ref2; git_signature * sig; git_blob * blob; + git_merge_head * merge_head; + std::string ui_message; }; @@ -246,7 +251,7 @@ namespace loot { } else { // Repository exists: check settings are correct, then pull updates. - git.ui_message = "An error occurred while trying to access the local masterlist repository."; + git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\"."; // Open the repository. BOOST_LOG_TRIVIAL(info) << "Existing repository found, attempting to open it."; @@ -279,6 +284,7 @@ namespace loot { BOOST_LOG_TRIVIAL(info) << "Received " << stats->indexed_objects << " of " << stats->total_objects << " objects in " << stats->received_bytes << " bytes."; // Check that a branch with the correct name exists. + git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\"."; int ret = git_branch_lookup(&git.ref, git.repo, repo_branch.c_str(), GIT_BRANCH_LOCAL); if (ret == GIT_ENOTFOUND) { // Branch doesn't exist. Create a new branch using the remote branch's latest commit. @@ -317,12 +323,40 @@ namespace loot { if (ret == 0) { /* The branch did exist, and is now pointed at by HEAD. - Need to merge the remote branch into it. - - 1. git_merge_head_from_fetchhead to get the remote branch object to merge with. - 2. git_merge to merge the remote branch object into HEAD, which is set to be - the desired branch.Docs say a commit may be necessary after this. + Need to merge the remote branch into it. Just do a fast-forward merge because + that's all that should be necessary as the local repo shouldn't get changed by + the user. */ + + BOOST_LOG_TRIVIAL(trace) << "Checking that local and remote branches can be merged by fast-forward."; + git_merge_analysis_t analysis; + git_merge_preference_t pref; + git.call(git_reference_lookup(&git.ref2, git.repo, (string("refs/remotes/origin/") + repo_branch).c_str())); + git.call(git_merge_head_from_ref(&git.merge_head, git.repo, git.ref2)); + git.call(git_merge_analysis(&analysis, &pref, git.repo, (const git_merge_head **)&git.merge_head, 1)); + + if (analysis == GIT_MERGE_ANALYSIS_FASTFORWARD) { + BOOST_LOG_TRIVIAL(trace) << "Local branch can be fast-forwarded to remote branch."; + // The remote branch reference points to a particular commit. We just want to + // update the local branch reference to point to the same commit. + // Get the commit object ID. + + const git_oid * commit_id = git_reference_target_peel(git.ref2); + git_reference_free(git.ref2); + git.ref2 = nullptr; + + git.call(git_reference_set_target(&git.ref2, git.ref, commit_id, git.sig, "Setting branch reference.")); + + git_reference_free(git.ref2); + git.ref2 = nullptr; + } + else if (analysis == GIT_MERGE_ANALYSIS_UP_TO_DATE) { + BOOST_LOG_TRIVIAL(trace) << "Local branch is up-to-date with remote branch."; + } + else { + throw error(error::git_error, "Local repository has been edited, an automatic fast-forward merge update is not possible."); + } + } // Free branch pointer. diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 06c5d395..fb45ce5a 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -110,24 +110,9 @@ struct masterlist_updater_parser { if (_doUpdate) { BOOST_LOG_TRIVIAL(debug) << "Updating masterlist"; try { - try { - pair ret = UpdateMasterlist(_game, _errors, _plugins, _messages); - _revision = ret.first; - _date = ret.second; - } - catch (loot::error &e) { - BOOST_LOG_TRIVIAL(error) << "Masterlist update failed. Details: " << e.what(); - if (e.code() == loot::error::git_error) { - BOOST_LOG_TRIVIAL(info) << "Masterlist update failure was due to Git error, deleting repository and retrying..."; - //Delete .git folder and try again. - fs::remove_all(_game.MasterlistPath().parent_path() / ".git"); - pair ret = UpdateMasterlist(_game, _errors, _plugins, _messages); - _revision = ret.first; - _date = ret.second; - } - else - throw e; - } + pair ret = UpdateMasterlist(_game, _errors, _plugins, _messages); + _revision = ret.first; + _date = ret.second; } catch (std::exception& e) { _plugins.clear(); _messages.clear();