static int check_remote_status(git_repository *repo, git_remote *origin, const char *branch, enum remote_transport rt) { int error = 0; git_reference *local_ref, *remote_ref; if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) return report_error("Git cache branch %s no longer exists", branch); if (git_branch_upstream(&remote_ref, local_ref)) { /* so there is no upstream branch for our branch; that's a problem. * let's push our branch */ git_strarray refspec; git_reference_list(&refspec, repo); #if USE_LIBGIT23_API git_push_options opts = GIT_PUSH_OPTIONS_INIT; if (rt == RT_SSH) opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) opts.callbacks.credentials = credential_https_cb; opts.callbacks.certificate_check = certificate_check_cb; error = git_remote_push(origin, &refspec, &opts); #else error = git_remote_push(origin, &refspec, NULL); #endif } else { error = try_to_update(repo, origin, local_ref, remote_ref, rt); git_reference_free(remote_ref); } git_reference_free(local_ref); return error; }
void test_network_remote_local__update_tips_for_new_remote(void) { git_repository *src_repo; git_repository *dst_repo; git_remote *new_remote; git_reference* branch; /* Copy test repo */ cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&src_repo, "testrepo.git")); /* Set up an empty bare repo to push into */ cl_git_pass(git_repository_init(&dst_repo, "./localbare.git", 1)); /* Push to bare repo */ cl_git_pass(git_remote_create(&new_remote, src_repo, "bare", "./localbare.git")); cl_git_pass(git_remote_push(new_remote, &push_array, NULL)); /* Make sure remote branch has been created */ cl_git_pass(git_branch_lookup(&branch, src_repo, "bare/master", GIT_BRANCH_REMOTE)); git_reference_free(branch); git_remote_free(new_remote); git_repository_free(dst_repo); cl_fixture_cleanup("localbare.git"); git_repository_free(src_repo); cl_fixture_cleanup("testrepo.git"); }
void test_refs_branches_delete__can_delete_a_remote_branch(void) { git_reference *branch; cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); }
void test_refs_branches_delete__can_delete_a_local_branch(void) { git_reference *branch; cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); }
void test_refs_branches_create__cannot_force_create_over_current_branch(void) { const git_oid *oid; git_reference *branch2; retrieve_known_commit(&target, repo); cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); cl_assert_equal_s("refs/heads/master", git_reference_name(branch2)); cl_assert_equal_i(true, git_branch_is_head(branch2)); oid = git_reference_target(branch2); cl_git_fail_with(-1, git_branch_create(&branch, repo, "master", target, 1, NULL, NULL)); branch = NULL; cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); cl_git_pass(git_oid_cmp(git_reference_target(branch), oid)); git_reference_free(branch2); }
void test_refs_branches_delete__can_delete_a_branch_when_HEAD_is_unborn(void) { git_reference *branch; make_head_unborn(repo, NON_EXISTING_HEAD); cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); }
static int create_branch( git_reference **ref_out, git_repository *repository, const char *branch_name, const git_commit *commit, const char *from, int force) { int is_unmovable_head = 0; git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT, log_message = GIT_BUF_INIT; int error = -1; int bare = git_repository_is_bare(repository); assert(branch_name && commit && ref_out); assert(git_object_owner((const git_object *)commit) == repository); if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) { error = git_branch_is_head(branch); git_reference_free(branch); branch = NULL; if (error < 0) goto cleanup; is_unmovable_head = error; } if (is_unmovable_head && force) { giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is " "the current HEAD of the repository.", branch_name); error = -1; goto cleanup; } if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0) goto cleanup; error = git_reference_create(&branch, repository, git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force, git_buf_cstr(&log_message)); if (!error) *ref_out = branch; cleanup: git_buf_free(&canonical_branch_name); git_buf_free(&log_message); return error; }
void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void) { git_reference *head; git_reference *branch; cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); git_reference_delete(head); git_reference_free(head); cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); }
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void) { git_reference *ref; int refs; fetchhead_test_clone(); refs = count_references(); fetchhead_test_fetch("refs/heads/first-merge", FETCH_HEAD_EXPLICIT_DATA); cl_git_fail(git_branch_lookup(&ref, g_repo, "first-merge", GIT_BRANCH_ALL)); cl_assert_equal_i(refs, count_references()); }
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void) { git_reference *head; git_reference *branch; /* Ensure HEAD targets the local master branch */ cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_git_fail(git_branch_delete(branch)); git_reference_free(branch); }
void test_refs_branches_delete__deleting_a_branch_removes_related_configuration_data(void) { git_reference *branch; assert_config_entry_existence(repo, "branch.track-local.remote", true); assert_config_entry_existence(repo, "branch.track-local.merge", true); cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); assert_config_entry_existence(repo, "branch.track-local.remote", false); assert_config_entry_existence(repo, "branch.track-local.merge", false); }
void test_online_fetchhead__explicit_dst_refspec_creates_branch(void) { git_reference *ref; int refs; fetchhead_test_clone(); refs = count_references(); fetchhead_test_fetch("refs/heads/first-merge:refs/heads/explicit-refspec", FETCH_HEAD_EXPLICIT_DATA); cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL)); cl_assert_equal_i(refs + 1, count_references()); git_reference_free(ref); }
// Helper method to normalize branch lookups. static inline int rugged_branch_lookup(git_reference **branch, git_repository *repo, VALUE rb_name_or_branch) { if (rb_obj_is_kind_of(rb_name_or_branch, rb_cRuggedBranch)) { rb_name_or_branch = rb_funcall(rb_name_or_branch, rb_intern("canonical_name"), 0); if (TYPE(rb_name_or_branch) != T_STRING) rb_raise(rb_eTypeError, "Expected #canonical_name to return a String"); return git_reference_lookup(branch, repo, StringValueCStr(rb_name_or_branch)); } else if (TYPE(rb_name_or_branch) == T_STRING) { char *branch_name = StringValueCStr(rb_name_or_branch), *ref_name; int error; if (strncmp(branch_name, "refs/heads/", strlen("refs/heads/")) == 0 || strncmp(branch_name, "refs/remotes/", strlen("refs/remotes/")) == 0) return git_reference_lookup(branch, repo, branch_name); if ((error = git_branch_lookup(branch, repo, branch_name, GIT_BRANCH_LOCAL)) == GIT_OK || error != GIT_ENOTFOUND) return error; if ((error = git_branch_lookup(branch, repo, branch_name, GIT_BRANCH_REMOTE)) == GIT_OK || error != GIT_ENOTFOUND) return error; ref_name = xmalloc((strlen(branch_name) + strlen("refs/") + 1) * sizeof(char)); strcpy(ref_name, "refs/"); strcat(ref_name, branch_name); error = git_reference_lookup(branch, repo, ref_name); xfree(ref_name); return error; } else { rb_raise(rb_eTypeError, "Expecting a String or Rugged::Branch instance"); } }
static void do_prune(git_repository *repo, const char *name) { git_reference *branch; int err; err = git_branch_lookup(&branch, repo, name, GIT_BRANCH_LOCAL); if (err != 0) { gbr_perror("git_branch_lookup()"); return; } if (git_branch_delete(branch) != 0) { gbr_perror("git_branch_delete()"); git_reference_free(branch); } }
void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void) { git_reference *head, *branch; cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); /* Detach HEAD and make it target the commit that "master" points to */ git_repository_detach_head(repo); cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); }
static void assert_branch_matches_name( const char *expected, const char *lookup_as) { git_reference *ref; git_buf b = GIT_BUF_INIT; cl_git_pass(git_branch_lookup(&ref, repo, lookup_as, GIT_BRANCH_LOCAL)); cl_git_pass(git_buf_sets(&b, "refs/heads/")); cl_git_pass(git_buf_puts(&b, expected)); cl_assert_equal_s(b.ptr, git_reference_name(ref)); cl_git_pass( git_oid_cmp(git_reference_target(ref), git_commit_id(target))); git_reference_free(ref); git_buf_free(&b); }
PyObject * Repository_lookup_branch(Repository *self, PyObject *args) { git_reference *c_reference; const char *c_name; git_branch_t branch_type = GIT_BRANCH_LOCAL; int err; if (!PyArg_ParseTuple(args, "s|I", &c_name, &branch_type)) return NULL; err = git_branch_lookup(&c_reference, self->repo, c_name, branch_type); if (err == 0) return wrap_branch(c_reference, self); if (err == GIT_ENOTFOUND) Py_RETURN_NONE; return Error_set(err); }
static int check_remote_status(git_repository *repo, git_remote *origin, const char *remote, const char *branch, enum remote_transport rt) { int error = 0; git_reference *local_ref, *remote_ref; if (verbose) fprintf(stderr, "git storage: check remote status\n"); if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) { if (is_subsurface_cloud) return cleanup_local_cache(remote, branch); else return report_error("Git cache branch %s no longer exists", branch); } if (git_branch_upstream(&remote_ref, local_ref)) { /* so there is no upstream branch for our branch; that's a problem. * let's push our branch */ git_strarray refspec; git_reference_list(&refspec, repo); git_push_options opts = GIT_PUSH_OPTIONS_INIT; opts.callbacks.transfer_progress = &transfer_progress_cb; auth_attempt = 0; if (rt == RT_SSH) opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) opts.callbacks.credentials = credential_https_cb; opts.callbacks.certificate_check = certificate_check_cb; git_storage_update_progress(translate("gettextFromC", "Store data into cloud storage")); error = git_remote_push(origin, &refspec, &opts); } else { error = try_to_update(repo, origin, local_ref, remote_ref, remote, branch, rt); git_reference_free(remote_ref); } git_reference_free(local_ref); return error; }
void test_refs_branches_delete__removes_reflog(void) { git_reference *branch; git_reflog *log; git_oid oidzero = {{0}}; git_signature *sig; /* Ensure the reflog has at least one entry */ cl_git_pass(git_signature_now(&sig, "Me", "*****@*****.**")); cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local")); cl_git_pass(git_reflog_append(log, &oidzero, sig, "message")); cl_assert(git_reflog_entrycount(log) > 0); git_signature_free(sig); git_reflog_free(log); cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); /* Reading a nonexistant reflog creates it, but it should be empty */ cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local")); cl_assert_equal_i(0, git_reflog_entrycount(log)); git_reflog_free(log); }
void GitRepository::branch(const QString& name) { git_repository* repo = repository(); git_auto<git_reference> branch; int err = git_branch_lookup(&branch, repo, name.toLatin1(), GIT_BRANCH_LOCAL); if (err == GIT_ENOTFOUND){ git_oid parent_id; git_auto<git_commit> parent; git_eval(git_reference_name_to_id(&parent_id, repo, "HEAD")); git_eval(git_commit_lookup(&parent, repo, &parent_id)); git_eval(git_branch_create(&branch, repo, name.toLocal8Bit(), parent, 1)); }else{ git_eval(err); } git_eval(git_repository_set_head(repo, git_reference_name(branch))); git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; opts.checkout_strategy = GIT_CHECKOUT_FORCE; git_eval(git_checkout_head(repo, &opts)); }
int git_branch_set_upstream(git_reference *branch, const char *upstream_name) { git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; git_reference *upstream; git_repository *repo; git_remote *remote = NULL; git_config *config; const char *name, *shortname; int local, error; const git_refspec *fetchspec; name = git_reference_name(branch); if (!git_reference__is_branch(name)) return not_a_local_branch(name); if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; shortname = name + strlen(GIT_REFS_HEADS_DIR); if (upstream_name == NULL) return unset_upstream(config, shortname); repo = git_reference_owner(branch); /* First we need to figure out whether it's a branch or remote-tracking */ if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) local = 1; else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) local = 0; else { giterr_set(GITERR_REFERENCE, "Cannot set upstream for branch '%s'", shortname); return GIT_ENOTFOUND; } /* * If it's local, the remote is "." and the branch name is * simply the refname. Otherwise we need to figure out what * the remote-tracking branch's name on the remote is and use * that. */ if (local) error = git_buf_puts(&value, "."); else error = git_branch_remote_name(&value, repo, git_reference_name(upstream)); if (error < 0) goto on_error; if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; if (local) { git_buf_clear(&value); if (git_buf_puts(&value, git_reference_name(upstream)) < 0) goto on_error; } else { /* Get the remoe-tracking branch's refname in its repo */ if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); remote = NULL; } git_buf_clear(&key); if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); return 0; on_error: git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); git_remote_free(remote); return -1; }
int cmd_checkout(git_repository *repo, int argc, char **argv) { int i, err, rc; char *branch; git_reference *branch_ref; git_checkout_options checkout_opts; branch = NULL; rc = EXIT_FAILURE; for (i=1;i<argc;i++) { if (argv[i][0] != '-') { if (!branch) branch = argv[i]; } else { } } if (!branch) { fprintf (stderr, "USAGE: %s <branch>\n", argv[0]); return -1; } /* Try local branch */ if (git_branch_lookup(&branch_ref,repo,branch,GIT_BRANCH_LOCAL) != 0) { /* No, try remote branch */ git_reference *remote_branch_ref; char remote_buf[256]; snprintf(remote_buf,sizeof(remote_buf),"%s/%s","origin",branch); if (git_branch_lookup(&remote_branch_ref, repo, remote_buf, GIT_BRANCH_REMOTE) == 0) { /* Exists, now try to create a local one from that reference */ if ((err = git2_create_branch_from_ref(&branch_ref,remote_branch_ref,repo,branch)) != 0) { fprintf(stderr,"Error code %d\n",err); libgit_error(); goto out; } git_reference_free(remote_branch_ref); } else { branch_ref = NULL; } } printf("Checking out %s\n",branch_ref?git_reference_name(branch_ref):branch); if ((err = git_repository_set_head(repo,branch_ref?git_reference_name(branch_ref):branch)) != 0) { fprintf(stderr,"Error code %d\n",err); libgit_error(); goto out; } /* Default options. Note by default we perform a dry checkout */ memset(&checkout_opts,0,sizeof(checkout_opts)); checkout_opts.version = GIT_CHECKOUT_OPTIONS_VERSION; checkout_opts.notify_cb = notify_cb; checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE|GIT_CHECKOUT_REMOVE_UNTRACKED;//GIT_CHECKOUT_SAFE|GIT_CHECKOUT_UPDATE_UNTRACKED; if (git_checkout_head(repo,&checkout_opts) != 0) { libgit_error(); goto out; } rc = EXIT_SUCCESS; out: if (branch_ref) git_reference_free(branch_ref); return rc; }
/** * Merge branch into HEAD * * @param branch S4 class git_branch to merge into HEAD. * @param merger Who is performing the merge * @param commit_on_success Commit merge commit, if one was created * during a normal merge * @return S4 class git_merge_result */ SEXP git2r_merge_branch(SEXP branch, SEXP merger, SEXP commit_on_success) { int err; SEXP result = R_NilValue; const char *name; git_buf buf = GIT_BUF_INIT; git_branch_t type; git_annotated_commit **merge_heads = NULL; git_reference *reference = NULL; git_repository *repository = NULL; git_signature *who = NULL; if (git2r_arg_check_branch(branch)) git2r_error(__func__, NULL, "'branch'", git2r_err_branch_arg); if (git2r_arg_check_logical(commit_on_success)) git2r_error(__func__, NULL, "'commit_on_success'", git2r_err_logical_arg); if (git2r_arg_check_signature(merger)) git2r_error(__func__, NULL, "'merger'", git2r_err_signature_arg); err = git2r_signature_from_arg(&who, merger); if (err) goto cleanup; repository = git2r_repository_open(GET_SLOT(branch, Rf_install("repo"))); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); name = CHAR(STRING_ELT(GET_SLOT(branch, Rf_install("name")), 0)); type = INTEGER(GET_SLOT(branch, Rf_install("type")))[0]; err = git_branch_lookup(&reference, repository, name, type); if (err) goto cleanup; merge_heads = calloc(1, sizeof(git_annotated_commit*)); if (NULL == merge_heads) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); goto cleanup; } err = git_annotated_commit_from_ref( &(merge_heads[0]), repository, reference); if (err) goto cleanup; err = git_buf_printf(&buf, "merge %s", name); if (err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_merge_result"))); err = git2r_merge( result, repository, (const git_annotated_commit **)merge_heads, 1, GIT_MERGE_PREFERENCE_NONE, buf.ptr, who, LOGICAL(commit_on_success)[0]); cleanup: git_buf_free(&buf); if (who) git_signature_free(who); if (merge_heads) git2r_merge_heads_free(merge_heads, 1); if (reference) git_reference_free(reference); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }
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; }
int main() { git_libgit2_init(); git_repository* rep = nullptr; git_rebase* prebase = nullptr; git_rebase_options rebase_opt = GIT_REBASE_OPTIONS_INIT; git_reference* onto_branch = nullptr; git_annotated_commit* onto = nullptr; git_rebase_operation* operation = nullptr; size_t entrycount; size_t current; git_signature* me = nullptr; git_index* index = nullptr; git_oid new_commit; int error = 0; // git open git_repository_open(&rep, path); error = git_rebase_open(&prebase, rep, &rebase_opt); // There is no rebase in progress if (error == GIT_ENOTFOUND) { git_branch_lookup(&onto_branch, rep, "new", GIT_BRANCH_LOCAL); git_annotated_commit_from_ref(&onto, rep, onto_branch); git_rebase_init(&prebase, rep, nullptr /* current branch */, nullptr /* upstream */ , onto /* branch to rebase onto */, &rebase_opt); } else if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } entrycount = git_rebase_operation_entrycount(prebase); std::cout<< "rebase entry count: " << entrycount << "\n"; while (git_rebase_next(&operation, prebase) != GIT_ITEROVER) { current = git_rebase_operation_current(prebase); // (called `init` but not yet `next`) then this returns `GIT_REBASE_NO_OPERATION` std::cout<< "rebase current index: " << current << "\n"; if (GIT_REBASE_NO_OPERATION == current) { std::cout<< "rebase no operation" << "\n"; } operation = git_rebase_operation_byindex(prebase, 0); } // reslove conflicts git_repository_index(&index, rep); if (git_index_has_conflicts(index)) { // git checkout --theirs git_checkout_options opt = GIT_CHECKOUT_OPTIONS_INIT; opt.checkout_strategy |= GIT_CHECKOUT_USE_THEIRS; git_checkout_index(rep, index, &opt); } // add git_index_update_all(index, nullptr, nullptr, nullptr); git_index_write(index); // commit git_signature_now(&me, "XiaochenFTX", "*****@*****.**"); git_rebase_commit(&new_commit, prebase, me, me, "UTF-8", "new rebase"); error = git_rebase_finish(prebase, me); if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } // git_rebase_abort(prebase); git_rebase_free(prebase); SHUTDOWN: git_repository_free(rep); git_libgit2_shutdown(); return 0; }