From 48f237e33e661bdfb48c33a0418e121ba75e107f Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Mon, 13 Sep 2021 22:01:56 -0700 Subject: [PATCH] cli: correctly update to remote's default branch after clone It turns out that `FETCH_HEAD` is not the remote's `HEAD` (it's actually not even a normal symbolic ref; it contains many lines of commits and names). We're supposed to ask the remote for its default branch instead. That's what this patch does. --- lib/src/git.rs | 16 ++++++++++++++-- src/commands.rs | 28 ++++++++++++++++------------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lib/src/git.rs b/lib/src/git.rs index 075b6d8ce..ee437ae4d 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -127,7 +127,7 @@ pub fn fetch( mut_repo: &mut MutableRepo, git_repo: &git2::Repository, remote_name: &str, -) -> Result<(), GitFetchError> { +) -> Result, GitFetchError> { let mut remote = git_repo .find_remote(remote_name) @@ -149,10 +149,22 @@ pub fn fetch( fetch_options.prune(FetchPrune::On); let refspec: &[&str] = &[]; remote.fetch(refspec, Some(&mut fetch_options), None)?; + // TODO: We could make it optional to get the default branch since we only care + // about it on clone. + let mut default_branch = None; + if let Ok(default_ref_buf) = remote.default_branch() { + if let Some(default_ref) = default_ref_buf.as_str() { + // LocalBranch here is the local branch on the remote, so it's really the remote + // branch + if let Some(RefName::LocalBranch(branch_name)) = parse_git_ref(default_ref) { + default_branch = Some(branch_name); + } + } + } import_refs(mut_repo, git_repo).map_err(|err| match err { GitImportError::InternalGitError(source) => GitFetchError::InternalGitError(source), })?; - Ok(()) + Ok(default_branch) } #[derive(Error, Debug, PartialEq)] diff --git a/src/commands.rs b/src/commands.rs index 71efbfdbb..19b498a73 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3271,18 +3271,22 @@ fn cmd_git_clone( let remote_name = "origin"; git_repo.remote(remote_name, source).unwrap(); let mut tx = repo.start_transaction("fetch from git remote into empty repo"); - git::fetch(tx.mut_repo(), &git_repo, remote_name).map_err(|err| match err { - GitFetchError::NoSuchRemote(_) => { - panic!("should't happen as we just created the git remote") - } - GitFetchError::InternalGitError(err) => { - CommandError::UserError(format!("Fetch failed: {:?}", err)) - } - })?; - if let Ok(fetch_head_ref) = git_repo.find_reference("FETCH_HEAD") { - if let Ok(fetch_head_git_commit) = fetch_head_ref.peel_to_commit() { - let fetch_head_id = CommitId(fetch_head_git_commit.id().as_bytes().to_vec()); - if let Ok(fetch_head_commit) = repo.store().get_commit(&fetch_head_id) { + let maybe_default_branch = + git::fetch(tx.mut_repo(), &git_repo, remote_name).map_err(|err| match err { + GitFetchError::NoSuchRemote(_) => { + panic!("should't happen as we just created the git remote") + } + GitFetchError::InternalGitError(err) => { + CommandError::UserError(format!("Fetch failed: {:?}", err)) + } + })?; + if let Some(default_branch) = maybe_default_branch { + let default_branch_target = tx + .mut_repo() + .view() + .get_remote_branch(&default_branch, "origin"); + if let Some(RefTarget::Normal(commit_id)) = default_branch_target { + if let Ok(fetch_head_commit) = repo.store().get_commit(&commit_id) { tx.mut_repo().check_out(ui.settings(), &fetch_head_commit); } }