/** * Set the remote's url in the configuration * * This assumes the common case of a single-url remote and * will otherwise raise an error. * @param repo S4 class git_repository * @param name The name of the remote * @param url The url to set * @return R_NilValue */ SEXP git2r_remote_set_url(SEXP repo, SEXP name, SEXP url) { int err; git_repository *repository = NULL; if (git2r_arg_check_string(name)) git2r_error(__func__, NULL, "'name'", git2r_err_string_arg); if (git2r_arg_check_string(url)) git2r_error(__func__, NULL, "'url'", git2r_err_string_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); err = git_remote_set_url( repository, CHAR(STRING_ELT(name, 0)), CHAR(STRING_ELT(url, 0))); if (repository) git_repository_free(repository); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return R_NilValue; }
/* * call-seq: * remote.url = url -> url * * Sets the remote's url without persisting it in the config. * Existing connections will not be updated. * remote.url = 'git://github.com/libgit2/rugged.git' #=> "git://github.com/libgit2/rugged.git" */ static VALUE rb_git_remote_set_url(VALUE self, VALUE rb_url) { git_remote *remote; rugged_validate_remote_url(rb_url); Data_Get_Struct(self, git_remote, remote); rugged_exception_check( git_remote_set_url(remote, StringValueCStr(rb_url)) ); return rb_url; }
/* * call-seq: * remote.url = url -> url * * Sets the remote's url without persisting it in the config. * Existing connections will not be updated. * * remote.url = 'git://github.com/libgit2/rugged.git' #=> "git://github.com/libgit2/rugged.git" */ static VALUE rb_git_remote_set_url(VALUE self, VALUE rb_url) { git_remote *remote; Check_Type(rb_url, T_STRING); Data_Get_Struct(self, git_remote, remote); rugged_exception_check( git_remote_set_url(remote, StringValueCStr(rb_url)) ); return rb_url; }
int Remote_url__set__(Remote *self, PyObject* py_url) { int err; char* url = NULL; url = py_str_to_c_str(py_url, NULL); if (url != NULL) { err = git_remote_set_url(self->remote, url); free(url); if (err == GIT_OK) return 0; Error_set(err); } return -1; }
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; }
void Gitarre::onPushAction () { Repository *repo = Repos[RepoView->currentIndex().row()]; // TODO: Add remote selection git_remote *remote = repo->GetRemote(0); struct git_remote_callbacks cb = { 1, Gitarre::sRProgressCb, Gitarre::sRCompletionCb, Gitarre::sRCredentialsCb, Gitarre::sRTransferProgressCb, Gitarre::sRUpdateTipsCb, (void *)this }; git_remote_set_callbacks (remote, &cb); // fix git protocol address const char *url = git_remote_url (remote); if (!strncmp (url, "git@", 4)) { int len = strlen (url) - 4; char *_url = (char *) malloc (len + 9); strcpy (_url, "https://"); strncpy (_url + 8, url + 4, len); _url [len + 8] = 0; char *sc = strrchr (_url, ':'); if (sc) *sc = '/'; git_remote_set_url (remote, _url); } StatusLabel->show(); StatusLabel->setText ("Connecting to remote..."); StatusProgress->show(); StatusProgress->setRange (0,0); git_remote_connect (remote, GIT_DIRECTION_PUSH); if (git_remote_connected (remote)) { git_push *push; git_push_new (&push, remote); git_push_add_refspec (push, "refs/heads/master:refs/heads/master"); git_push_set_callbacks (push, Gitarre::sPPackbuilderProgressCb, (void *)this, Gitarre::sPTransferProgressCb, (void *)this); git_push_finish (push); if (git_push_unpack_ok (push)) { git_push_status_foreach (push, Gitarre::sPStatusForeachCb, (void *)this); git_push_update_tips (push); } git_push_free (push); git_remote_disconnect (remote); git_remote_free (remote); } else { const git_error *error = giterr_last (); if (error->message) QMessageBox::warning(this, "Connect to remote", QString ("Failed to connect to ") + git_remote_url (remote) + " :\n" + error->message); else QMessageBox::warning(this, "Connect to remote", QString ("Failed to connect to ") + git_remote_url (remote)); } StatusLabel->hide(); StatusProgress->hide(); }