int git_reference__update_for_commit( git_repository *repo, git_reference *ref, const char *ref_name, const git_oid *id, const git_signature *committer, const char *operation) { git_reference *ref_new = NULL; git_commit *commit = NULL; git_buf reflog_msg = GIT_BUF_INIT; int error; if ((error = git_commit_lookup(&commit, repo, id)) < 0 || (error = git_buf_printf(&reflog_msg, "%s%s: %s", operation ? operation : "commit", git_commit_parentcount(commit) == 0 ? " (initial)" : "", git_commit_summary(commit))) < 0) goto done; if (ref) error = git_reference_set_target( &ref_new, ref, id, committer, git_buf_cstr(&reflog_msg)); else error = git_reference__update_terminal( repo, ref_name, id, committer, git_buf_cstr(&reflog_msg)); done: git_reference_free(ref_new); git_buf_free(&reflog_msg); git_commit_free(commit); return error; }
/** * ggit_ref_set_target: * @ref: a #GgitRef. * @oid: a #GgitOId. * @log_message: The one line long message to be appended to the reflog. * @error: a #GError for error reporting, or %NULL. * * Create a new reference with the same name as the given reference but a * different OID target. The reference must be a direct reference, otherwise * this will fail. * * The new reference will be written to disk, overwriting the given reference. * * Returns: (transfer full): the newly created #GgitRef. */ GgitRef * ggit_ref_set_target (GgitRef *ref, GgitOId *oid, const gchar *log_message, GError **error) { git_reference *out; gint ret; g_return_val_if_fail (ref != NULL, NULL); g_return_val_if_fail (oid != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = git_reference_set_target (&out, _ggit_native_get (ref), _ggit_oid_get_oid (oid), log_message); if (ret != GIT_OK) { _ggit_error_set (error, ret); return NULL; } return _ggit_ref_wrap (out, FALSE); }
int Reference_oid__set__(Reference *self, PyObject *py_hex) { git_oid oid; int err; git_reference *new_ref; CHECK_REFERENCE_INT(self); /* Get the oid */ err = py_str_to_git_oid_expand(git_reference_owner(self->reference), py_hex, &oid); if (err < 0) { Error_set(err); return -1; } /* Set the oid */ err = git_reference_set_target(&new_ref, self->reference, &oid); if (err < 0) { Error_set(err); return -1; } git_reference_free(self->reference); self->reference = new_ref; return 0; }
/* * The remote is strictly newer than the local branch. */ static int reset_to_remote(git_repository *repo, git_reference *local, const git_oid *new_id) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_object *target; // If it's not checked out (bare or not HEAD), just update the reference */ if (git_repository_is_bare(repo) || git_branch_is_head(local) != 1) { git_reference *out; if (git_reference_set_target(&out, local, new_id, "Update to remote")) return report_error("Could not update local ref to newer remote ref"); git_reference_free(out); // Not really an error, just informational report_error("Updated local branch from remote"); return 0; } if (git_object_lookup(&target, repo, new_id, GIT_OBJ_COMMIT)) return report_error("Could not look up remote commit"); opts.checkout_strategy = GIT_CHECKOUT_SAFE; if (git_reset(repo, target, GIT_RESET_HARD, &opts)) return report_error("Local head checkout failed after update"); // Not really an error, just informational report_error("Updated local information from remote"); return 0; }
void test_refs_settargetwithlog__updating_a_direct_reference_adds_a_reflog_entry(void) { git_reference *reference, *reference_out; git_oid current_id, target_id; git_signature *signature; git_reflog *reflog; const git_reflog_entry *entry; const char *message = "You've been logged, mate!"; git_oid_fromstr(¤t_id, br2_tip); git_oid_fromstr(&target_id, master_tip); cl_git_pass(git_reference_lookup(&reference, g_repo, br2_name)); cl_git_pass(git_signature_now(&signature, "foo", "foo@bar")); cl_git_pass(git_reference_set_target( &reference_out, reference, &target_id, signature, message)); cl_git_pass(git_reflog_read(&reflog, g_repo, br2_name)); entry = git_reflog_entry_byindex(reflog, 0); cl_assert(git_oid_cmp(¤t_id, &entry->oid_old) == 0); cl_assert(git_oid_cmp(&target_id, &entry->oid_cur) == 0); cl_assert_equal_s(message, entry->msg); git_reflog_free(reflog); git_reference_free(reference_out); git_reference_free(reference); git_signature_free(signature); }
PyObject * Reference_set_target(Reference *self, PyObject *args, PyObject *kwds) { git_oid oid; char *c_name; int err; git_reference *new_ref; const git_signature *sig = NULL; PyObject *py_target = NULL; Signature *py_signature = NULL; const char *message = NULL; char *keywords[] = {"target", "signature", "message", NULL}; CHECK_REFERENCE(self); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O!s", keywords, &py_target, &SignatureType, &py_signature, &message)) return NULL; if (py_signature) sig = py_signature->signature; /* Case 1: Direct */ if (GIT_REF_OID == git_reference_type(self->reference)) { err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid); if (err < 0) goto error; err = git_reference_set_target(&new_ref, self->reference, &oid, sig, message); if (err < 0) goto error; git_reference_free(self->reference); self->reference = new_ref; Py_RETURN_NONE; } /* Case 2: Symbolic */ c_name = py_path_to_c_str(py_target); if (c_name == NULL) return NULL; err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, sig, message); free(c_name); if (err < 0) goto error; git_reference_free(self->reference); self->reference = new_ref; Py_RETURN_NONE; error: Error_set(err); return NULL; }
void test_stash_save__cannot_stash_against_an_unborn_branch(void) { git_reference *head; cl_git_pass(git_reference_lookup(&head, repo, "HEAD")); cl_git_pass(git_reference_set_target(head, "refs/heads/unborn")); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); git_reference_free(head); }
int luagi_reference_gen_set_target( lua_State *L, const char *tablename ) { git_reference **ref = luaL_checkudata( L, 1, tablename ); git_oid oid; if( luagi_check_oid( &oid, L, 2 ) ) { ltk_error_abort( L ); } const char *log_message = luaL_checkstring( L, 4 ); git_reference **out = lua_newuserdata( L, sizeof( git_reference * ) ); if( git_reference_set_target( out, *ref, &oid, log_message ) ) { return ltk_push_git_error( L ); } ltk_setmetatable( L, LUAGI_REFERENCE_FUNCS ); return 1; }
/* * The remote is strictly newer than the local branch. */ static int reset_to_remote(git_repository *repo, git_reference *local, const git_oid *new_id) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; opts.progress_cb = &progress_cb; git_object *target; if (verbose) fprintf(stderr, "git storage: reset to remote\n"); // If it's not checked out (bare or not HEAD), just update the reference */ if (git_repository_is_bare(repo) || git_branch_is_head(local) != 1) { git_reference *out; if (git_reference_set_target(&out, local, new_id, "Update to remote")) return report_error(translate("gettextFromC", "Could not update local cache to newer remote data")); git_reference_free(out); #ifdef DEBUG // Not really an error, just informational report_error("Updated local branch from remote"); #endif return 0; } if (git_object_lookup(&target, repo, new_id, GIT_OBJ_COMMIT)) { if (is_subsurface_cloud) return report_error(translate("gettextFromC", "Subsurface cloud storage corrupted")); else return report_error("Could not look up remote commit"); } opts.checkout_strategy = GIT_CHECKOUT_SAFE; if (git_reset(repo, target, GIT_RESET_HARD, &opts)) { if (is_subsurface_cloud) return report_error(translate("gettextFromC", "Could not update local cache to newer remote data")); else return report_error("Local head checkout failed after update"); } // Not really an error, just informational #ifdef DEBUG report_error("Updated local information from remote"); #endif return 0; }
int Reference_target__set__(Reference *self, PyObject *py_target) { git_oid oid; char *c_name; int err; git_reference *new_ref; CHECK_REFERENCE_INT(self); /* Case 1: Direct */ if (GIT_REF_OID == git_reference_type(self->reference)) { err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid); if (err < 0) return err; err = git_reference_set_target(&new_ref, self->reference, &oid); if (err < 0) goto error; git_reference_free(self->reference); self->reference = new_ref; return 0; } /* Case 2: Symbolic */ c_name = py_path_to_c_str(py_target); if (c_name == NULL) return -1; err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name); free(c_name); if (err < 0) goto error; git_reference_free(self->reference); self->reference = new_ref; return 0; error: Error_set(err); return -1; }
void test_refs_reflog_messages__updating_a_direct_reference(void) { git_reference *ref, *ref_out, *target_ref; git_oid target_id; const char *message = "You've been logged, mate!"; git_reference_name_to_id(&target_id, g_repo, "refs/heads/haacked"); cl_git_pass(git_reference_lookup(&target_ref, g_repo, "refs/heads/haacked")); cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master")); cl_git_pass(git_reference_set_target(&ref_out, ref, &target_id, message)); cl_reflog_check_entry(g_repo, "refs/heads/master", 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "258f0e2a959a364e40ed6603d5d44fbb24765b10", NULL, message); git_reference_free(target_ref); git_reference_free(ref); git_reference_free(ref_out); }
static int update_head(git_repository *repo, git_object *commit) { int error; git_reference *head = NULL, *target = NULL; error = git_repository_head(&head, repo); if (error < 0 && error != GIT_EORPHANEDHEAD) return error; if (error == GIT_EORPHANEDHEAD) { giterr_clear(); /* * TODO: This is a bit weak as this doesn't support chained * symbolic references. yet. */ if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) goto cleanup; if ((error = git_reference_create( &target, repo, git_reference_symbolic_target(head), git_object_id(commit), 0)) < 0) goto cleanup; } else { if ((error = git_reference_set_target(head, git_object_id(commit))) < 0) goto cleanup; } error = 0; cleanup: git_reference_free(head); git_reference_free(target); return error; }
/** * Advances the ref with the given name, causing it to point to the object * with the given id. */ static int sync_fast_forward(git_repository *repo, const char *name, git_oid *id) { int e = 0; git_reference *old_ref = NULL; git_reference *new_ref = NULL; e = git_reference_lookup(&old_ref, repo, name); if (!e) { git_reference_set_target(&new_ref, old_ref, id, "fast-forward"); } else if (e == GIT_ENOTFOUND) { git_check(git_reference_create(&new_ref, repo, name, id, 0, "create branch")); } exit: if (old_ref) git_reference_free(old_ref); if (new_ref) git_reference_free(new_ref); return e; }
void SyncState::sync() { m_timer.restart(); // Set up directory structure, if necessary std::string tmpPath = cpp3ds::FileSystem::getFilePath("sdmc:/3ds/BrewMan/tmp"); std::string cachePath = cpp3ds::FileSystem::getFilePath("sdmc:/3ds/BrewMan/cache"); std::string installedPath = cpp3ds::FileSystem::getFilePath("sdmc:/3ds/BrewMan/installed"); if (pathExists(tmpPath.c_str(), false)) removeDirectory(tmpPath.c_str()); mkdir(tmpPath.c_str(), 0777); if (!pathExists(cachePath.c_str(), false)) mkdir(cachePath.c_str(), 0777); if (!pathExists(installedPath.c_str(), false)) mkdir(installedPath.c_str(), 0777); // If auto-dated, boot into newest BrewMan if (autoUpdate()) { char buf[256]; size_t len; FILE *src = fopen("sdmc:/3ds/BrewMan/tmp/update.3dsx", "rb"); FILE *dst = fopen("sdmc:/3ds/BrewMan/tmp/update-copy.3dsx", "wb"); while ((len = fread(buf, 1, sizeof(buf), src)) > 0) fwrite(buf, 1, sizeof(buf), dst); fclose(src); fclose(dst); bootApp("/3ds/BrewMan/tmp/update.3dsx", ""); requestStackClear(); return; } git_repository *repo = NULL; const char *repoUrl = "git://github.com/Repo3DS/ideal-enigma.git"; const std::string path = cpp3ds::FileSystem::getFilePath(REPO_DIR); git_clone_options opts = GIT_CLONE_OPTIONS_INIT; setStatus("Fetching git repo..."); int error = git_clone(&repo, repoUrl, path.c_str(), NULL); if (error < 0) { if (error == GIT_EEXISTS) { error = git_repository_open(&repo, path.c_str()); if (error == 0) { git_remote *remote; error = git_remote_lookup(&remote, repo, "origin"); if (error == 0) { error = git_remote_fetch(remote, NULL, NULL, "pull"); if (error == 0) { git_annotated_commit *our_head, *their_heads[1]; if (git_repository_fetchhead_foreach(repo, find_master, NULL) == 0) { git_annotated_commit_from_fetchhead(&their_heads[0], repo, "master", repoUrl, &m_git_oid); git_merge_analysis_t analysis; git_merge_preference_t prefs; git_merge_analysis(&analysis, &prefs, repo, (const git_annotated_commit**)their_heads, 1); if (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) printf("up to date\n"); else if (analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) { printf("fast-forwarding\n"); // if (git_merge(repo, (const git_annotated_commit **)their_heads, 1, NULL, NULL) == 0) { git_reference *ref; git_reference *newref; if (git_reference_lookup(&ref, repo, "refs/heads/master") == 0) git_reference_set_target(&newref, ref, &m_git_oid, "BrewMan pull: Fast-forward"); git_reset_from_annotated(repo, their_heads[0], GIT_RESET_HARD, NULL); git_reference_free(ref); git_repository_state_cleanup(repo); } git_annotated_commit_free(their_heads[0]); } } } } git_repository_free(repo); const git_error *e = giterr_last(); if (e) { setStatus(_("Error %d/%d\n%s\nCloning repo again...", error, e->klass, e->message)); if (!removeDirectory(path.c_str())) { cpp3ds::sleep(cpp3ds::seconds(2.f)); sync(); } else { setStatus("Repo failure. Please report this error.\nAnd delete /3ds/BrewMan/repo/ and try again."); } return; } } const git_error *e = giterr_last(); if (e) { setStatus(_("Error %d/%d: %s", error, e->klass, e->message)); return; } } setStatus("Everything up-to-date!"); // Give the Title animation time to finish if necessary while (m_timer.getElapsedTime() < cpp3ds::seconds(5.f)) cpp3ds::sleep(cpp3ds::milliseconds(50)); requestStackClear(); requestStackPush(States::Browse); }
/** * Perform a fast-forward merge * * @param merge_result S4 class git_merge_result * @param merge_head The merge head to fast-forward merge * @param repository The repository * @param log_message First part of the one line long message in the reflog * @return 0 on success, or error code */ static int git2r_fast_forward_merge( SEXP merge_result, const git_annotated_commit *merge_head, git_repository *repository, const char *log_message) { int err; const git_oid *oid; git_buf buf = GIT_BUF_INIT; git_commit *commit = NULL; git_tree *tree = NULL; git_reference *reference = NULL; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; oid = git_annotated_commit_id(merge_head); err = git_commit_lookup(&commit, repository, oid); if (err) goto cleanup; err = git_commit_tree(&tree, commit); if (err) goto cleanup; opts.checkout_strategy = GIT_CHECKOUT_SAFE; err = git_checkout_tree(repository, (git_object*)tree, &opts); if (err) goto cleanup; err = git_repository_head(&reference, repository); if (err) { if (GIT_ENOTFOUND != err) goto cleanup; } err = git_buf_printf(&buf, "%s: Fast-forward", log_message); if (err) goto cleanup; if (GIT_ENOTFOUND == err) { err = git_reference_create( &reference, repository, "HEAD", git_commit_id(commit), 0, /* force */ buf.ptr); } else { git_reference *target_ref = NULL; err = git_reference_set_target( &target_ref, reference, git_commit_id(commit), buf.ptr); if (target_ref) git_reference_free(target_ref); } SET_SLOT( merge_result, Rf_install("fast_forward"), ScalarLogical(1)); SET_SLOT( merge_result, Rf_install("conflicts"), ScalarLogical(0)); cleanup: git_buf_free(&buf); if (commit) git_commit_free(commit); if (reference) git_reference_free(reference); if (tree) git_tree_free(tree); return err; }
bool Masterlist::Update(const boost::filesystem::path& path, const std::string& repoUrl, const std::string& repoBranch) { GitHelper git; fs::path repoPath = path.parent_path(); string filename = path.filename().string(); if (repoUrl.empty() || repoBranch.empty()) throw std::invalid_argument("Repository URL and branch must not be empty."); // Initialise checkout options. BOOST_LOG_TRIVIAL(debug) << "Setting up checkout options."; char * paths = new char[filename.length() + 1]; strcpy(paths, filename.c_str()); git.GetData().checkout_options.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_REMOVE_EXISTING; git.GetData().checkout_options.paths.strings = &paths; git.GetData().checkout_options.paths.count = 1; // Initialise clone options. git.GetData().clone_options.checkout_opts = git.GetData().checkout_options; git.GetData().clone_options.bare = 0; git.GetData().clone_options.checkout_branch = repoBranch.c_str(); // Now try to access the repository if it exists, or clone one if it doesn't. BOOST_LOG_TRIVIAL(trace) << "Attempting to open the Git repository at: " << repoPath; if (!git.IsRepository(repoPath)) git.Clone(repoPath, repoUrl); else { // Repository exists: check settings are correct, then pull updates. git.SetErrorMessage((boost::format(translate("An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str()); // Open the repository. BOOST_LOG_TRIVIAL(info) << "Existing repository found, attempting to open it."; git.Call(git_repository_open(&git.GetData().repo, repoPath.string().c_str())); // Set the remote URL. BOOST_LOG_TRIVIAL(info) << "Using remote URL: " << repoUrl; git.Call(git_remote_set_url(git.GetData().repo, "origin", repoUrl.c_str())); // Now fetch updates from the remote. git.Fetch("origin"); // Check that a local branch with the correct name exists. git.SetErrorMessage((boost::format(translate("An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str()); int ret = git_branch_lookup(&git.GetData().reference, git.GetData().repo, repoBranch.c_str(), GIT_BRANCH_LOCAL); if (ret == GIT_ENOTFOUND) // Branch doesn't exist. Create a new branch using the remote branch's latest commit. git.CheckoutNewBranch("origin", repoBranch); else { // The local branch exists. Need to merge the remote branch // into it. git.Call(ret); // Handle other errors from preceding branch lookup. // Check if HEAD points to the desired branch and set it to if not. if (!git_branch_is_head(git.GetData().reference)) { BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << repoBranch; git.Call(git_repository_set_head(git.GetData().repo, (string("refs/heads/") + repoBranch).c_str())); } // Get remote branch reference. git.Call(git_branch_upstream(&git.GetData().reference2, git.GetData().reference)); BOOST_LOG_TRIVIAL(trace) << "Checking HEAD and remote branch's mergeability."; git_merge_analysis_t analysis; git_merge_preference_t pref; git.Call(git_annotated_commit_from_ref(&git.GetData().annotated_commit, git.GetData().repo, git.GetData().reference2)); git.Call(git_merge_analysis(&analysis, &pref, git.GetData().repo, (const git_annotated_commit **)&git.GetData().annotated_commit, 1)); if ((analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) == 0 && (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) == 0) { // The local branch can't be easily merged. Best just to delete and recreate it. BOOST_LOG_TRIVIAL(trace) << "Local branch cannot be easily merged with remote branch."; BOOST_LOG_TRIVIAL(trace) << "Deleting the local branch."; git.Call(git_branch_delete(git.GetData().reference)); // Need to free ref before calling git.CheckoutNewBranch() git_reference_free(git.GetData().reference); git.GetData().reference = nullptr; git_reference_free(git.GetData().reference2); git.GetData().reference2 = nullptr; git.CheckoutNewBranch("origin", repoBranch); } else { // Get remote branch commit ID. git.Call(git_reference_peel(&git.GetData().object, git.GetData().reference2, GIT_OBJ_COMMIT)); const git_oid * remote_commit_id = git_object_id(git.GetData().object); git_object_free(git.GetData().object); git.GetData().object = nullptr; git_reference_free(git.GetData().reference2); git.GetData().reference2 = nullptr; bool updateBranchHead = true; 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. BOOST_LOG_TRIVIAL(trace) << "Local branch is up-to-date with remote branch."; BOOST_LOG_TRIVIAL(trace) << "Checking to see if local and remote branch heads are equal."; // Get local branch commit ID. git.Call(git_reference_peel(&git.GetData().object, git.GetData().reference, GIT_OBJ_COMMIT)); const git_oid * local_commit_id = git_object_id(git.GetData().object); git_object_free(git.GetData().object); git.GetData().object = nullptr; updateBranchHead = local_commit_id->id != remote_commit_id->id; // If the masterlist in // HEAD also matches the masterlist file, no further // action needs to be taken. Otherwise, a checkout // must be performed and the checked-out file parsed. if (!updateBranchHead) { BOOST_LOG_TRIVIAL(trace) << "Local and remote branch heads are equal."; if (!GitHelper::IsFileDifferent(repoPath, filename)) { BOOST_LOG_TRIVIAL(info) << "Local branch and masterlist file are already up to date."; return false; } } else BOOST_LOG_TRIVIAL(trace) << "Local branch heads is ahead of remote branch head."; } else BOOST_LOG_TRIVIAL(trace) << "Local branch can be fast-forwarded to remote branch."; if (updateBranchHead) { // The remote branch reference points to a particular // commit. Update the local branch reference to point // to the same commit. BOOST_LOG_TRIVIAL(trace) << "Syncing local branch head with remote branch head."; git.Call(git_reference_set_target(&git.GetData().reference2, git.GetData().reference, remote_commit_id, "Setting branch reference.")); git_reference_free(git.GetData().reference2); git.GetData().reference2 = nullptr; } git_reference_free(git.GetData().reference); git.GetData().reference = nullptr; BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD."; git.Call(git_checkout_head(git.GetData().repo, &git.GetData().checkout_options)); } } } // Now whether the repository was cloned or updated, the working directory contains // the latest masterlist. Try parsing it: on failure, detach the HEAD back one commit // and try again. bool parsingFailed = false; std::string parsingError; git.SetErrorMessage((boost::format(translate("An error occurred while trying to read information on the updated masterlist. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str()); do { // Get the HEAD revision's short ID. string revision = git.GetHeadShortId(); //Now try parsing the masterlist. BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing."; try { this->Load(path); parsingFailed = false; } catch (std::exception& e) { parsingFailed = true; if (parsingError.empty()) parsingError = boost::locale::translate("Masterlist revision").str() + " " + string(revision) + ": " + e.what() + ". " + boost::locale::translate("The latest masterlist revision contains a syntax error, LOOT is using the most recent valid revision instead. Syntax errors are usually minor and fixed within hours.").str(); //There was an error, roll back one revision. BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + string(revision) + ": " + e.what(); git.CheckoutRevision("HEAD^"); } } while (parsingFailed); if (!parsingError.empty()) AppendMessage(Message(MessageType::error, parsingError)); return true; }
static int try_to_git_merge(git_repository *repo, git_reference *local, git_reference *remote, git_oid *base, const git_oid *local_id, const git_oid *remote_id) { git_tree *local_tree, *remote_tree, *base_tree; git_commit *local_commit, *remote_commit, *base_commit; git_index *merged_index; git_merge_options merge_options; if (verbose) { char outlocal[41], outremote[41]; outlocal[40] = outremote[40] = 0; git_oid_fmt(outlocal, local_id); git_oid_fmt(outremote, remote_id); fprintf(stderr, "trying to merge local SHA %s remote SHA %s\n", outlocal, outremote); } git_merge_init_options(&merge_options, GIT_MERGE_OPTIONS_VERSION); #ifdef USE_LIBGIT23_API merge_options.tree_flags = GIT_MERGE_TREE_FIND_RENAMES; #else merge_options.flags = GIT_MERGE_TREE_FIND_RENAMES; #endif merge_options.file_favor = GIT_MERGE_FILE_FAVOR_UNION; merge_options.rename_threshold = 100; if (git_commit_lookup(&local_commit, repo, local_id)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit (%s)"), giterr_last()->message); if (git_commit_tree(&local_tree, local_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed local tree lookup (%s)"), giterr_last()->message); if (git_commit_lookup(&remote_commit, repo, remote_id)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit (%s)"), giterr_last()->message); if (git_commit_tree(&remote_tree, remote_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed remote tree lookup (%s)"), giterr_last()->message); if (git_commit_lookup(&base_commit, repo, base)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit: (%s)"), giterr_last()->message); if (git_commit_tree(&base_tree, base_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed base tree lookup: (%s)"), giterr_last()->message); if (git_merge_trees(&merged_index, repo, base_tree, local_tree, remote_tree, &merge_options)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge failed (%s)"), giterr_last()->message); if (git_index_has_conflicts(merged_index)) { int error; const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL; git_index_conflict_iterator *iter = NULL; error = git_index_conflict_iterator_new(&iter, merged_index); while (git_index_conflict_next(&ancestor, &ours, &theirs, iter) != GIT_ITEROVER) { /* Mark this conflict as resolved */ fprintf(stderr, "conflict in %s / %s / %s -- ", ours ? ours->path : "-", theirs ? theirs->path : "-", ancestor ? ancestor->path : "-"); if ((!ours && theirs && ancestor) || (ours && !theirs && ancestor)) { // the file was removed on one side or the other - just remove it fprintf(stderr, "looks like a delete on one side; removing the file from the index\n"); error = git_index_remove(merged_index, ours ? ours->path : theirs->path, GIT_INDEX_STAGE_ANY); } else { error = git_index_conflict_remove(merged_index, ours ? ours->path : theirs ? theirs->path : ancestor->path); } if (error) { fprintf(stderr, "error at conflict resplution (%s)", giterr_last()->message); } } git_index_conflict_cleanup(merged_index); git_index_conflict_iterator_free(iter); report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge conflict - manual intervention needed")); } git_oid merge_oid, commit_oid; git_tree *merged_tree; git_signature *author; git_commit *commit; if (git_index_write_tree_to(&merge_oid, merged_index, repo)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: writing the tree failed (%s)"), giterr_last()->message); if (git_tree_lookup(&merged_tree, repo, &merge_oid)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: tree lookup failed (%s)"), giterr_last()->message); if (git_signature_default(&author, repo) < 0) return report_error(translate("gettextFromC", "Failed to get author: (%s)"), giterr_last()->message); if (git_commit_create_v(&commit_oid, repo, NULL, author, author, NULL, "automatic merge", merged_tree, 2, local_commit, remote_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: git commit create failed (%s)"), giterr_last()->message); if (git_commit_lookup(&commit, repo, &commit_oid)) return report_error(translate("gettextFromC", "Error: could not lookup the merge commit I just created (%s)"), giterr_last()->message); if (git_branch_is_head(local) && !git_repository_is_bare(repo)) { git_object *parent; git_reference_peel(&parent, local, GIT_OBJ_COMMIT); if (update_git_checkout(repo, parent, merged_tree)) { report_error("Warning: checked out branch is inconsistent with git data"); } } if (git_reference_set_target(&local, local, &commit_oid, "Subsurface merge event")) return report_error("Error: failed to update branch (%s)", giterr_last()->message); set_git_id(&commit_oid); git_signature_free(author); return 0; }
static int try_to_git_merge(git_repository *repo, git_reference **local_p, git_reference *remote, git_oid *base, const git_oid *local_id, const git_oid *remote_id) { UNUSED(remote); git_tree *local_tree, *remote_tree, *base_tree; git_commit *local_commit, *remote_commit, *base_commit; git_index *merged_index; git_merge_options merge_options; if (verbose) { char outlocal[41], outremote[41]; outlocal[40] = outremote[40] = 0; git_oid_fmt(outlocal, local_id); git_oid_fmt(outremote, remote_id); fprintf(stderr, "trying to merge local SHA %s remote SHA %s\n", outlocal, outremote); } git_merge_init_options(&merge_options, GIT_MERGE_OPTIONS_VERSION); #if !LIBGIT2_VER_MAJOR && LIBGIT2_VER_MINOR > 23 merge_options.flags = GIT_MERGE_FIND_RENAMES; #else merge_options.tree_flags = GIT_MERGE_TREE_FIND_RENAMES; #endif merge_options.file_favor = GIT_MERGE_FILE_FAVOR_UNION; merge_options.rename_threshold = 100; if (git_commit_lookup(&local_commit, repo, local_id)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&local_tree, local_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed local tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_lookup(&remote_commit, repo, remote_id)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&remote_tree, remote_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed local tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_lookup(&base_commit, repo, base)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&base_tree, base_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed base tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_merge_trees(&merged_index, repo, base_tree, local_tree, remote_tree, &merge_options)) { fprintf(stderr, "Remote storage and local data diverged. Error: merge failed (%s)", giterr_last()->message); // this is the one where I want to report more detail to the user - can't quite explain why return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge failed (%s)"), giterr_last()->message); } if (git_index_has_conflicts(merged_index)) { int error; const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL; git_index_conflict_iterator *iter = NULL; error = git_index_conflict_iterator_new(&iter, merged_index); while (git_index_conflict_next(&ancestor, &ours, &theirs, iter) != GIT_ITEROVER) { /* Mark this conflict as resolved */ fprintf(stderr, "conflict in %s / %s / %s -- ", ours ? ours->path : "-", theirs ? theirs->path : "-", ancestor ? ancestor->path : "-"); if ((!ours && theirs && ancestor) || (ours && !theirs && ancestor)) { // the file was removed on one side or the other - just remove it fprintf(stderr, "looks like a delete on one side; removing the file from the index\n"); error = git_index_remove(merged_index, ours ? ours->path : theirs->path, GIT_INDEX_STAGE_ANY); } else if (ancestor) { error = git_index_conflict_remove(merged_index, ours ? ours->path : theirs ? theirs->path : ancestor->path); } if (error) { fprintf(stderr, "error at conflict resplution (%s)", giterr_last()->message); } } git_index_conflict_cleanup(merged_index); git_index_conflict_iterator_free(iter); report_error(translate("gettextFromC", "Remote storage and local data diverged. Cannot combine local and remote changes")); } git_oid merge_oid, commit_oid; git_tree *merged_tree; git_signature *author; git_commit *commit; if (git_index_write_tree_to(&merge_oid, merged_index, repo)) goto write_error; if (git_tree_lookup(&merged_tree, repo, &merge_oid)) goto write_error; if (git_signature_default(&author, repo) < 0) if (git_signature_now(&author, "Subsurface", "noemail@given") < 0) goto write_error; if (git_commit_create_v(&commit_oid, repo, NULL, author, author, NULL, "automatic merge", merged_tree, 2, local_commit, remote_commit)) goto write_error; if (git_commit_lookup(&commit, repo, &commit_oid)) goto write_error; if (git_branch_is_head(*local_p) && !git_repository_is_bare(repo)) { git_object *parent; git_reference_peel(&parent, *local_p, GIT_OBJ_COMMIT); if (update_git_checkout(repo, parent, merged_tree)) { goto write_error; } } if (git_reference_set_target(local_p, *local_p, &commit_oid, "Subsurface merge event")) goto write_error; set_git_id(&commit_oid); git_signature_free(author); if (verbose) fprintf(stderr, "Successfully merged repositories"); return 0; diverged_error: return report_error(translate("gettextFromC", "Remote storage and local data diverged")); write_error: return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: writing the data failed (%s)"), giterr_last()->message); }
void Reference::setTarget(const OId& oid, const Signature &signature, const QString &message) { git_reference* rp; qGitThrow(git_reference_set_target(&rp, data(), oid.constData(), signature.data(), message.toUtf8())); d = ptr_type(rp, git_reference_free); }