git: Add CHERRY_PICK_HEAD to the list of merge heads (#26145)
Attempt to fix an issue where conflicts from a cherry-pick don't get cleared out of the git panel after being resolved. Release Notes: - Git Beta: Fixed resolution of conflicts from cherry-picks not being reflected in the git panel
This commit is contained in:
parent
431727fdd7
commit
5daadc0d30
2 changed files with 112 additions and 0 deletions
|
@ -427,6 +427,15 @@ impl GitRepository for RealGitRepository {
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
if let Some(oid) = self
|
||||||
|
.repository
|
||||||
|
.lock()
|
||||||
|
.find_reference("CHERRY_PICK_HEAD")
|
||||||
|
.ok()
|
||||||
|
.and_then(|reference| reference.target())
|
||||||
|
{
|
||||||
|
shas.push(oid.to_string())
|
||||||
|
}
|
||||||
shas
|
shas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use fs::{FakeFs, Fs, RealFs, RemoveOptions};
|
use fs::{FakeFs, Fs, RealFs, RemoveOptions};
|
||||||
use git::{
|
use git::{
|
||||||
|
repository::RepoPath,
|
||||||
status::{
|
status::{
|
||||||
FileStatus, GitSummary, StatusCode, TrackedStatus, TrackedSummary, UnmergedStatus,
|
FileStatus, GitSummary, StatusCode, TrackedStatus, TrackedSummary, UnmergedStatus,
|
||||||
UnmergedStatusCode,
|
UnmergedStatusCode,
|
||||||
|
@ -3307,6 +3308,87 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_conflicted_cherry_pick(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
cx.executor().allow_parking();
|
||||||
|
|
||||||
|
let root = TempTree::new(json!({
|
||||||
|
"project": {
|
||||||
|
"a.txt": "a",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let root_path = root.path();
|
||||||
|
|
||||||
|
let tree = Worktree::local(
|
||||||
|
root_path,
|
||||||
|
true,
|
||||||
|
Arc::new(RealFs::default()),
|
||||||
|
Default::default(),
|
||||||
|
&mut cx.to_async(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let repo = git_init(&root_path.join("project"));
|
||||||
|
git_add("a.txt", &repo);
|
||||||
|
git_commit("init", &repo);
|
||||||
|
|
||||||
|
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
tree.flush_fs_events(cx).await;
|
||||||
|
|
||||||
|
git_branch("other-branch", &repo);
|
||||||
|
git_checkout("refs/heads/other-branch", &repo);
|
||||||
|
std::fs::write(root_path.join("project/a.txt"), "A").unwrap();
|
||||||
|
git_add("a.txt", &repo);
|
||||||
|
git_commit("capitalize", &repo);
|
||||||
|
let commit = repo
|
||||||
|
.head()
|
||||||
|
.expect("Failed to get HEAD")
|
||||||
|
.peel_to_commit()
|
||||||
|
.expect("HEAD is not a commit");
|
||||||
|
git_checkout("refs/heads/master", &repo);
|
||||||
|
std::fs::write(root_path.join("project/a.txt"), "b").unwrap();
|
||||||
|
git_add("a.txt", &repo);
|
||||||
|
git_commit("improve letter", &repo);
|
||||||
|
git_cherry_pick(&commit, &repo);
|
||||||
|
std::fs::read_to_string(root_path.join("project/.git/CHERRY_PICK_HEAD"))
|
||||||
|
.expect("No CHERRY_PICK_HEAD");
|
||||||
|
pretty_assertions::assert_eq!(
|
||||||
|
git_status(&repo),
|
||||||
|
collections::HashMap::from_iter([("a.txt".to_owned(), git2::Status::CONFLICTED)])
|
||||||
|
);
|
||||||
|
tree.flush_fs_events(cx).await;
|
||||||
|
let conflicts = tree.update(cx, |tree, _| {
|
||||||
|
let entry = tree.git_entries().nth(0).expect("No git entry").clone();
|
||||||
|
entry
|
||||||
|
.current_merge_conflicts
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
});
|
||||||
|
pretty_assertions::assert_eq!(conflicts, [RepoPath::from("a.txt")]);
|
||||||
|
|
||||||
|
git_add("a.txt", &repo);
|
||||||
|
// Attempt to manually simulate what `git cherry-pick --continue` would do.
|
||||||
|
git_commit("whatevs", &repo);
|
||||||
|
std::fs::remove_file(root.path().join("project/.git/CHERRY_PICK_HEAD"))
|
||||||
|
.expect("Failed to remove CHERRY_PICK_HEAD");
|
||||||
|
pretty_assertions::assert_eq!(git_status(&repo), collections::HashMap::default());
|
||||||
|
tree.flush_fs_events(cx).await;
|
||||||
|
let conflicts = tree.update(cx, |tree, _| {
|
||||||
|
let entry = tree.git_entries().nth(0).expect("No git entry").clone();
|
||||||
|
entry
|
||||||
|
.current_merge_conflicts
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
});
|
||||||
|
pretty_assertions::assert_eq!(conflicts, []);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_private_single_file_worktree(cx: &mut TestAppContext) {
|
async fn test_private_single_file_worktree(cx: &mut TestAppContext) {
|
||||||
init_test(cx);
|
init_test(cx);
|
||||||
|
@ -3405,6 +3487,11 @@ fn git_commit(msg: &'static str, repo: &git2::Repository) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn git_cherry_pick(commit: &git2::Commit<'_>, repo: &git2::Repository) {
|
||||||
|
repo.cherrypick(commit, None).expect("Failed to cherrypick");
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn git_stash(repo: &mut git2::Repository) {
|
fn git_stash(repo: &mut git2::Repository) {
|
||||||
use git2::Signature;
|
use git2::Signature;
|
||||||
|
@ -3430,6 +3517,22 @@ fn git_reset(offset: usize, repo: &git2::Repository) {
|
||||||
.expect("Could not reset");
|
.expect("Could not reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn git_branch(name: &str, repo: &git2::Repository) {
|
||||||
|
let head = repo
|
||||||
|
.head()
|
||||||
|
.expect("Couldn't get repo head")
|
||||||
|
.peel_to_commit()
|
||||||
|
.expect("HEAD is not a commit");
|
||||||
|
repo.branch(name, &head, false).expect("Failed to commit");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn git_checkout(name: &str, repo: &git2::Repository) {
|
||||||
|
repo.set_head(name).expect("Failed to set head");
|
||||||
|
repo.checkout_head(None).expect("Failed to check out head");
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn git_status(repo: &git2::Repository) -> collections::HashMap<String, git2::Status> {
|
fn git_status(repo: &git2::Repository) -> collections::HashMap<String, git2::Status> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue