static int rebase_commit_merge( git_oid *commit_id, git_rebase *rebase, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_rebase_operation *operation; git_reference *head = NULL; git_commit *head_commit = NULL, *commit = NULL; git_index *index = NULL; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; int error; operation = git_array_get(rebase->operations, rebase->current); assert(operation); if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 || (error = git_repository_head(&head, rebase->repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || (error = git_repository_index(&index, rebase->repo)) < 0 || (error = rebase_commit__create(&commit, rebase, index, head_commit, author, committer, message_encoding, message)) < 0 || (error = git_reference__update_for_commit( rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0) goto done; git_oid_fmt(old_idstr, &operation->id); git_oid_fmt(new_idstr, git_commit_id(commit)); if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr)) < 0) goto done; git_oid_cpy(commit_id, git_commit_id(commit)); done: git_index_free(index); git_reference_free(head); git_commit_free(head_commit); git_commit_free(commit); return error; }
static int merge_dirty_files(char *dirty_files[]) { git_reference *head; git_object *head_object; int error; cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL)); write_files(dirty_files); error = merge_branch(); git_object_free(head_object); git_reference_free(head); return error; }
void test_refs_branches_tracking__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) { git_reference *head; git_repository *repository; git_commit *target; repository = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_repository_head(&head, repository)); cl_git_pass(git_reference_peel(((git_object **)&target), head, GIT_OBJ_COMMIT)); git_reference_free(head); assert_merge_and_or_remote_key_missing(repository, target, "remoteless"); assert_merge_and_or_remote_key_missing(repository, target, "mergeless"); assert_merge_and_or_remote_key_missing(repository, target, "mergeandremoteless"); git_commit_free(target); cl_git_sandbox_cleanup(); }
/** * Updates some entries in the index from the HEAD commit tree. * * @param repo S3 class git_repository * @param path The paths to reset * @return R_NilValue */ SEXP git2r_reset_default(SEXP repo, SEXP path) { int error = 0; git_strarray pathspec = {0}; git_reference *head = NULL; git_object *head_commit = NULL; git_repository *repository = NULL; if (git2r_arg_check_string_vec(path)) git2r_error(__func__, NULL, "'path'", git2r_err_string_vec_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); error = git2r_copy_string_vec(&pathspec, path); if (error || !pathspec.count) goto cleanup; error = git_repository_head(&head, repository); if (error) goto cleanup; error = git_reference_peel(&head_commit, head, GIT2R_OBJECT_COMMIT); if (error) goto cleanup; error = git_reset_default(repository, head_commit, &pathspec); cleanup: git_reference_free(head); git_object_free(head_commit); free(pathspec.strings); git_repository_free(repository); if (error) git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL); return R_NilValue; }
void test_submodule_init__relative_url_detached_head(void) { git_submodule *sm; git_config *cfg; git_buf absolute_url = GIT_BUF_INIT; const char *config_url; git_reference *head_ref = NULL; git_object *head_commit = NULL; g_repo = setup_fixture_submodule_simple(); /* Put the parent repository into a detached head state. */ cl_git_pass(git_repository_head(&head_ref, g_repo)); cl_git_pass(git_reference_peel(&head_commit, head_ref, GIT_OBJ_COMMIT)); cl_git_pass(git_repository_set_head_detached(g_repo, git_commit_id((git_commit *)head_commit))); cl_assert(git_path_dirname_r(&absolute_url, git_repository_workdir(g_repo)) > 0); cl_git_pass(git_buf_joinpath(&absolute_url, absolute_url.ptr, "testrepo.git")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); /* verify that the .gitmodules is set with an absolute path*/ cl_assert_equal_s("../testrepo.git", git_submodule_url(sm)); /* init and verify that absolute path is written to .git/config */ cl_git_pass(git_submodule_init(sm, false)); cl_git_pass(git_repository_config_snapshot(&cfg, g_repo)); cl_git_pass(git_config_get_string(&config_url, cfg, "submodule.testrepo.url")); cl_assert_equal_s(absolute_url.ptr, config_url); git_buf_free(&absolute_url); git_config_free(cfg); git_object_free(head_commit); git_reference_free(head_ref); git_submodule_free(sm); }
static void assert_peel( const char *ref_name, git_otype requested_type, const char* expected_sha, git_otype expected_type) { git_oid expected_oid; git_reference *ref; git_object *peeled; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_git_pass(git_reference_peel(&peeled, ref, requested_type)); cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha)); cl_assert_equal_i(0, git_oid_cmp(&expected_oid, git_object_id(peeled))); cl_assert_equal_i(expected_type, git_object_type(peeled)); git_object_free(peeled); git_reference_free(ref); }
PyObject * Reference_peel(Reference *self, PyObject *args) { int err, type; git_object *obj; PyObject *py_type = Py_None; CHECK_REFERENCE(self); if (!PyArg_ParseTuple(args, "|O", &py_type)) return NULL; type = py_object_to_object_type(py_type); if (type == -1) return NULL; err = git_reference_peel(&obj, self->reference, type); if (err < 0) return Error_set(err); return wrap_object(obj, self->repo); }
//diffs workdir and index - ie unstaged changes //equivalent to `git diff` - WORKS int diff(git_repository* repo) { git_diff_list* diff; git_index* index; git_reference* ref_head; git_commit* head; git_tree* head_tree; git_repository_index(&index, repo); git_index_read(index); git_repository_head(&ref_head, repo); git_reference_peel((git_object**) &head, ref_head, GIT_OBJ_COMMIT); git_commit_tree(&head_tree, head); git_diff_index_to_workdir(&diff, repo, index, NULL); print_diff(diff); return 0; }
void test_repo_head__symref_chain(void) { git_signature *sig; git_oid id; git_tree *tree; git_reference *ref; const char *msg; size_t nentries, nentries_master; nentries = entrycount(repo, GIT_HEAD_FILE); cl_git_pass(git_signature_now(&sig, "me", "*****@*****.**")); cl_git_pass(git_repository_head(&ref, repo)); cl_git_pass(git_reference_peel((git_object **) &tree, ref, GIT_OBJ_TREE)); git_reference_free(ref); nentries_master = entrycount(repo, "refs/heads/master"); msg = "message 1"; cl_git_pass(git_reference_symbolic_create(&ref, repo, "refs/heads/master", "refs/heads/foo", 1, msg)); git_reference_free(ref); cl_assert_equal_i(0, entrycount(repo, "refs/heads/foo")); cl_assert_equal_i(nentries, entrycount(repo, GIT_HEAD_FILE)); cl_assert_equal_i(nentries_master, entrycount(repo, "refs/heads/master")); msg = "message 2"; cl_git_pass(git_commit_create(&id, repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL)); git_tree_free(tree); cl_assert_equal_i(1, entrycount(repo, "refs/heads/foo")); cl_assert_equal_i(nentries +1, entrycount(repo, GIT_HEAD_FILE)); cl_assert_equal_i(nentries_master, entrycount(repo, "refs/heads/master")); git_signature_free(sig); }
/* A repo that has a HEAD (even a properly born HEAD that peels to * a commit) but no index should be treated as if it's an empty baseline */ void test_checkout_tree__baseline_is_empty_when_no_index(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_reference *head; git_object *obj; git_status_list *status; size_t conflicts = 0; assert_on_branch(g_repo, "master"); cl_git_pass(git_repository_head(&head, g_repo)); cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL)); cl_must_pass(p_unlink("testrepo/.git/index")); /* for a safe checkout, we should have checkout conflicts with * the existing untracked files. */ opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; opts.notify_cb = checkout_conflict_count_cb; opts.notify_payload = &conflicts; cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, obj, &opts)); cl_assert_equal_i(4, conflicts); /* but force should succeed and update the index */ opts.checkout_strategy |= GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(git_status_list_new(&status, g_repo, NULL)); cl_assert_equal_i(0, git_status_list_entrycount(status)); git_status_list_free(status); git_object_free(obj); git_reference_free(head); }
/* * revert the same commit twice (when the first reverts cleanly): * * git revert 2d440f2 * git revert 2d440f2 */ void test_revert_workdir__again(void) { git_reference *head_ref; git_commit *orig_head; git_tree *reverted_tree; git_oid reverted_tree_oid, reverted_commit_oid; git_signature *signature; struct merge_index_entry merge_index_entries[] = { { 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 0, "file1.txt" }, { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&orig_head, head_ref, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL)); cl_git_pass(git_revert(repo, orig_head, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index)); cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "*****@*****.**", time(NULL), 0)); cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); cl_git_pass(git_revert(repo, orig_head, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); git_signature_free(signature); git_tree_free(reverted_tree); git_commit_free(orig_head); git_reference_free(head_ref); }
void test_refs_reflog_messages__commit_on_symbolic_ref_updates_head_reflog(void) { git_signature *sig; git_oid id; git_tree *tree; git_reference *ref1, *ref2; const char *msg; size_t nentries_head, nentries_master; nentries_head = reflog_entrycount(g_repo, GIT_HEAD_FILE); cl_git_pass(git_signature_now(&sig, "me", "*****@*****.**")); cl_git_pass(git_repository_head(&ref1, g_repo)); cl_git_pass(git_reference_peel((git_object **) &tree, ref1, GIT_OBJ_TREE)); nentries_master = reflog_entrycount(g_repo, "refs/heads/master"); msg = "message 1"; cl_git_pass(git_reference_symbolic_create(&ref2, g_repo, "refs/heads/master", "refs/heads/foo", 1, msg)); cl_assert_equal_i(0, reflog_entrycount(g_repo, "refs/heads/foo")); cl_assert_equal_i(nentries_head, reflog_entrycount(g_repo, GIT_HEAD_FILE)); cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master")); msg = "message 2"; cl_git_pass(git_commit_create(&id, g_repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL)); cl_assert_equal_i(1, reflog_entrycount(g_repo, "refs/heads/foo")); cl_assert_equal_i(nentries_head + 1, reflog_entrycount(g_repo, GIT_HEAD_FILE)); cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master")); git_signature_free(sig); git_reference_free(ref1); git_reference_free(ref2); git_tree_free(tree); }
/* git revert --no-commit HEAD */ void test_revert_workdir__head(void) { git_reference *head; git_commit *commit; struct merge_index_entry merge_index_entries[] = { { 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 0, "file1.txt" }, { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; /* HEAD is 2d440f2b3147d3dc7ad1085813478d6d869d5a4d */ cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&commit, head, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); cl_assert(merge_test_workdir(repo, merge_index_entries, 4)); git_reference_free(head); git_commit_free(commit); }
static int return_to_orig_head(git_rebase *rebase) { git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; git_commit *terminal_commit = NULL; git_buf branch_msg = GIT_BUF_INIT, head_msg = GIT_BUF_INIT; char onto[GIT_OID_HEXSZ]; int error = 0; git_oid_fmt(onto, &rebase->onto_id); if ((error = git_buf_printf(&branch_msg, "rebase finished: %s onto %.*s", rebase->orig_head_name, GIT_OID_HEXSZ, onto)) == 0 && (error = git_buf_printf(&head_msg, "rebase finished: returning to %s", rebase->orig_head_name)) == 0 && (error = git_repository_head(&terminal_ref, rebase->repo)) == 0 && (error = git_reference_peel((git_object **)&terminal_commit, terminal_ref, GIT_OBJ_COMMIT)) == 0 && (error = git_reference_create_matching(&branch_ref, rebase->repo, rebase->orig_head_name, git_commit_id(terminal_commit), 1, &rebase->orig_head_id, branch_msg.ptr)) == 0) error = git_reference_symbolic_create(&head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, head_msg.ptr); git_buf_free(&head_msg); git_buf_free(&branch_msg); git_commit_free(terminal_commit); git_reference_free(head_ref); git_reference_free(branch_ref); git_reference_free(terminal_ref); return error; }
void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE_HEAD_file_existence(void) { git_index *index; git_reference *head; git_buf merge_head_path = GIT_BUF_INIT; cl_git_sandbox_cleanup(); repo = cl_git_sandbox_init("mergedrepo"); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_i(true, git_index_has_conflicts(index)); git_index_free(index); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT)); git_reference_free(head); cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT)); }
int git_checkout_head( git_repository *repo, git_checkout_opts *opts) { git_reference *head; int error; git_object *tree = NULL; assert(repo); if ((error = git_repository_head(&head, repo)) < 0) return error; if ((error = git_reference_peel(&tree, head, GIT_OBJ_TREE)) < 0) goto cleanup; error = git_checkout_tree(repo, tree, opts); cleanup: git_reference_free(head); git_object_free(tree); return error; }
void QGit::unstageFiles(QStringList items) { QVector<QByteArray> tmpStrList; git_repository *repo = nullptr; git_reference *head = nullptr; git_object *head_commit = nullptr; git_strarray paths = {nullptr, 0}; int res = 0; QGitError error; try { if (items.count() == 0) { throw QGitError(); } res = git_repository_open(&repo, m_path.absolutePath().toUtf8().constData()); if (res) { throw QGitError("git_repository_open", res); } paths.count = static_cast<size_t>(items.count()); paths.strings = static_cast<char **>(malloc(sizeof(char *) * static_cast<size_t>(items.count()))); if (paths.strings == nullptr) { throw QGitError("malloc", 0); } tmpStrList.reserve(items.count()); for(int c = 0; c < items.count(); c++) { tmpStrList.append(items.at(c).toUtf8()); paths.strings[c] = const_cast<char *>(tmpStrList.at(c).data()); } res = git_repository_head(&head, repo); if (res == 0) { res = git_reference_peel(&head_commit, head, GIT_OBJ_COMMIT); if (res) { throw QGitError("git_reference_peel", res); } } res = git_reset_default(repo, head_commit, &paths); if (res) { throw QGitError("git_reset_default", res); } } catch(const QGitError &ex) { error = ex; } emit unstageFilesReply(error); if (paths.strings) { free(paths.strings); paths.strings = nullptr; } paths.count = 0; if (head_commit) { git_object_free(head_commit); head_commit = nullptr; } if (head) { git_reference_free(head); head = nullptr; } if (repo) { git_repository_free(repo); repo = nullptr; } }
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; }
void test_submodule_update__update_already_checked_out_submodule(void) { git_submodule *sm = NULL; git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT; git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT; unsigned int submodule_status = 0; git_reference *branch_reference = NULL; git_object *branch_commit = NULL; struct update_submodule_cb_payload update_payload = { 0 }; g_repo = setup_fixture_submodule_simple(); update_options.checkout_opts.progress_cb = checkout_progress_cb; update_options.checkout_opts.progress_payload = &update_payload; /* Initialize and update the sub repository */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); cl_git_pass(git_submodule_status(&submodule_status, sm)); cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_WD_UNINITIALIZED); cl_git_pass(git_submodule_update(sm, 1, &update_options)); /* verify expected state */ cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); /* checkout the alternate_1 branch */ checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE; cl_git_pass(git_reference_lookup(&branch_reference, g_repo, "refs/heads/alternate_1")); cl_git_pass(git_reference_peel(&branch_commit, branch_reference, GIT_OBJ_COMMIT)); cl_git_pass(git_checkout_tree(g_repo, branch_commit, &checkout_options)); cl_git_pass(git_repository_set_head(g_repo, git_reference_name(branch_reference))); /* * Verify state after checkout of parent repository. The submodule ID in the * HEAD commit and index should be updated, but not the workdir. */ cl_git_pass(git_submodule_status(&submodule_status, sm)); cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS_WD_MODIFIED); cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); /* * Update the submodule and verify the state. * Now, the HEAD, index, and Workdir commits should all be updated to * the new commit. */ cl_git_pass(git_submodule_update(sm, 0, &update_options)); cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); /* verify that the expected callbacks have been called. */ cl_assert_equal_i(1, update_payload.checkout_progress_called); git_submodule_free(sm); git_object_free(branch_commit); git_reference_free(branch_reference); }
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); }
/* git revert --no-commit 72333f47d4e83616630ff3b0ffe4c0faebcc3c45 */ void test_revert_workdir__conflicts(void) { git_reference *head_ref; git_commit *head, *commit; git_oid revert_oid; git_buf conflicting_buf = GIT_BUF_INIT, mergemsg_buf = GIT_BUF_INIT; struct merge_index_entry merge_index_entries[] = { { 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 1, "file1.txt" }, { 0100644, "4b8fcff56437e60f58e9a6bc630dd242ebf6ea2c", 2, "file1.txt" }, { 0100644, "3a3ef367eaf3fe79effbfb0a56b269c04c2b59fe", 3, "file1.txt" }, { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; git_oid_fromstr(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head, head_ref, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); cl_git_pass(git_futils_readbuffer(&conflicting_buf, TEST_REPO_PATH "/file1.txt")); cl_assert(strcmp(conflicting_buf.ptr, "!File one!\n" \ "!File one!\n" \ "File one!\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "<<<<<<< HEAD\n" \ "File one!\n" \ "!File one!\n" \ "!File one!\n" \ "!File one!\n" \ "=======\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ ">>>>>>> parent of 72333f4... automergeable changes\n") == 0); cl_assert(git_path_exists(TEST_REPO_PATH "/.git/MERGE_MSG")); cl_git_pass(git_futils_readbuffer(&mergemsg_buf, TEST_REPO_PATH "/.git/MERGE_MSG")); cl_assert(strcmp(mergemsg_buf.ptr, "Revert \"automergeable changes\"\n" \ "\n" \ "This reverts commit 72333f47d4e83616630ff3b0ffe4c0faebcc3c45.\n" "\n" \ "Conflicts:\n" \ "\tfile1.txt\n") == 0); git_commit_free(commit); git_commit_free(head); git_reference_free(head_ref); git_buf_free(&mergemsg_buf); git_buf_free(&conflicting_buf); }
static int rebase_commit_merge( git_oid *commit_id, git_rebase *rebase, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_index *index = NULL; git_reference *head = NULL; git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL; git_rebase_operation *operation; git_tree *head_tree = NULL, *tree = NULL; git_diff *diff = NULL; git_oid tree_id; git_buf reflog_msg = GIT_BUF_INIT; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; int error; operation = git_array_get(rebase->operations, rebase->current); assert(operation); if ((error = git_repository_index(&index, rebase->repo)) < 0) goto done; if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "Conflicts have not been resolved"); error = GIT_EMERGECONFLICT; goto done; } if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_repository_head(&head, rebase->repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || (error = git_commit_tree(&head_tree, head_commit)) < 0 || (error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) == 0) { giterr_set(GITERR_REBASE, "This patch has already been applied"); error = GIT_EAPPLIED; goto done; } if ((error = git_index_write_tree(&tree_id, index)) < 0 || (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) goto done; if (!author) author = git_commit_author(current_commit); if (!message) { message_encoding = git_commit_message_encoding(current_commit); message = git_commit_message(current_commit); } if ((error = git_commit_create(commit_id, rebase->repo, NULL, author, committer, message_encoding, message, tree, 1, (const git_commit **)&head_commit)) < 0 || (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 || (error = git_reference__update_for_commit( rebase->repo, NULL, "HEAD", commit_id, "rebase")) < 0) goto done; git_oid_fmt(old_idstr, git_commit_id(current_commit)); git_oid_fmt(new_idstr, commit_id); error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); done: git_buf_free(&reflog_msg); git_commit_free(commit); git_diff_free(diff); git_tree_free(tree); git_tree_free(head_tree); git_commit_free(head_commit); git_commit_free(current_commit); git_reference_free(head); git_index_free(index); return error; }
void PmrWorkspace::stageFile(const QString &pPath, bool pStage) { // Un/stage the file, which path is given, and let people know of the // outcome if (isOpen()) { QByteArray relativePathByteArray = QDir(mPath).relativeFilePath(pPath).toUtf8(); const char *relativePath = relativePathByteArray.constData(); bool success = false; git_index *index; if (git_repository_index(&index, mGitRepository) == GIT_OK) { if (pStage) { uint statusFlags = 0; git_status_file(&statusFlags, mGitRepository, relativePath); if ((statusFlags & GIT_STATUS_WT_DELETED) != 0) { success = git_index_remove_bypath(index, relativePath) == GIT_OK; } else { success = git_index_add_bypath(index, relativePath) == GIT_OK; } } else if (git_repository_head_unborn(mGitRepository) == 1) { success = git_index_remove_bypath(index, relativePath) == GIT_OK; } else { // We need to add a "reset stage" to the index, which means // getting the tree for HEAD and tree_entry for the file git_reference *head; if (git_repository_head(&head, mGitRepository) == GIT_OK) { git_tree *headTree; if (git_reference_peel(reinterpret_cast<git_object **>(&headTree), head, GIT_OBJECT_TREE) == GIT_OK) { git_tree_entry *headEntry; if (git_tree_entry_bypath(&headEntry, headTree, relativePath) == GIT_OK) { git_index_entry indexEntry; memset(&indexEntry, '\0', sizeof(git_index_entry)); indexEntry.id = *git_tree_entry_id(headEntry); indexEntry.mode = uint32_t(git_tree_entry_filemode(headEntry)); indexEntry.path = relativePath; git_index_add(index, &indexEntry); git_tree_entry_free(headEntry); success = true; } else { success = git_index_remove_bypath(index, relativePath) == GIT_OK; } git_tree_free(headTree); } git_reference_free(head); } } if (success) { git_index_write(index); } git_index_free(index); } if (!success) { emitGitError(tr("An error occurred while trying to stage %1.").arg(pPath)); } } }
static void checkout(git_repository *repo) { git_reference *master_ref, *remote_ref, *HEAD_ref, *tmpr; git_checkout_options co_opts; const char *remote_br_name; git_commit *remote_commit; git_object *remote_obj; char *remotebr; int rc; remotebr = NULL; xasprintf(&remotebr, "refs/remotes/%s/%s", option_origin, option_trunk); rc = git_reference_lookup(&remote_ref, repo, remotebr); if (rc) die("git_reference_lookup(%s): %d", remotebr, rc); rc = git_branch_name(&remote_br_name, remote_ref); if (rc) die("git_branch_name: %d", rc); rc = git_reference_peel(&remote_obj, remote_ref, GIT_OBJ_COMMIT); if (rc) die("git_reference_peel"); rc = git_commit_lookup(&remote_commit, repo, git_object_id(remote_obj)); if (rc) die("git_commit_lookup"); rc = git_branch_create(&master_ref, repo, "master", remote_commit, false, NULL, NULL); if (rc) die("git_branch_create: %d", rc); rc = git_reference_symbolic_create(&HEAD_ref, repo, "HEAD", "refs/heads/master", false, NULL, NULL); if (rc && rc != GIT_EEXISTS) die("git_reference_symbolic_create: %d", rc); rc = git_branch_set_upstream(master_ref, remote_br_name); if (rc) /* TODO: '' is not a valid remote name */ #if 0 die("git_branch_set_upstream: %d (%d/%s)", rc, giterr_last()->klass, giterr_last()->message); #else printf("XXXgit_branch_set_upstream: %d (%d/%s)\n", rc, giterr_last()->klass, giterr_last()->message); #endif rc = git_reference_lookup(&tmpr, repo, "refs/heads/master"); if (rc) die("%s: reference_lookup: master doesn't exist?", __func__); if (git_reference_cmp(tmpr, master_ref) != 0) die("mismatched master"); co_opts = (git_checkout_options) GIT_CHECKOUT_OPTIONS_INIT; co_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; rc = git_checkout_head(repo, &co_opts); if (rc) die("git_checkout_head"); free(remotebr); git_commit_free(remote_commit); git_object_free(remote_obj); git_reference_free(tmpr); git_reference_free(HEAD_ref); git_reference_free(master_ref); git_reference_free(remote_ref); }
void test_submodule_update__can_force_update(void) { git_submodule *sm = NULL; git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT; git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT; unsigned int submodule_status = 0; git_reference *branch_reference = NULL; git_object *branch_commit = NULL; g_repo = setup_fixture_submodule_simple(); /* Initialize and update the sub repository */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); cl_git_pass(git_submodule_status(&submodule_status, sm)); cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_WD_UNINITIALIZED); cl_git_pass(git_submodule_update(sm, 1, &update_options)); /* verify expected state */ cl_assert(git_oid_streq(git_submodule_head_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); /* checkout the alternate_1 branch */ checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE; cl_git_pass(git_reference_lookup(&branch_reference, g_repo, "refs/heads/alternate_1")); cl_git_pass(git_reference_peel(&branch_commit, branch_reference, GIT_OBJ_COMMIT)); cl_git_pass(git_checkout_tree(g_repo, branch_commit, &checkout_options)); cl_git_pass(git_repository_set_head(g_repo, git_reference_name(branch_reference))); /* * Verify state after checkout of parent repository. The submodule ID in the * HEAD commit and index should be updated, but not the workdir. */ cl_git_pass(git_submodule_status(&submodule_status, sm)); cl_assert_equal_i(submodule_status, GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS_WD_MODIFIED); cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); /* * Create a conflicting edit in the subrepository to verify that * the submodule update action is blocked. */ cl_git_write2file("submodule_simple/testrepo/branch_file.txt", "a conflicting edit", 0, O_WRONLY | O_CREAT | O_TRUNC, 0777); /* forcefully checkout and verify the submodule state was updated. */ update_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_submodule_update(sm, 0, &update_options)); cl_assert(git_oid_streq(git_submodule_head_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0); git_submodule_free(sm); git_object_free(branch_commit); git_reference_free(branch_reference); }