fix(vcs): Label restored local changes as yours after Smart Checkout; name the branch checked out

Conflicts from restoring stashed changes show the user's uncommitted
changes on the left like other operations, and the checkout notification
names the new branch instead of the previous one.
Цей коміт міститься в:
l0ng-ai committed 2026-10-25 09:34:36 +08:00
1 джерело e1eb12c0c2
коміт 7df5747418
5 files changed
+22

No files matched your search

+6
Переглянути файл
@@ -56,6 +56,12 @@ pub(crate) fn merge_sides(r: &Repo) -> IdeResult<MergeSides> {
}
Some("cherry-pick") => sides.commit = read("CHERRY_PICK_HEAD").map(short),
Some("revert") => sides.commit = read("REVERT_HEAD").map(short),
// Conflicts outside an operation come from restoring stashed changes (Smart
// Checkout, update with autostash): stage 2 is the new HEAD, stage 3 the user's.
None if !crate::write::unmerged_paths(r)?.is_empty() => {
sides.operation = Some("unstash".into());
sides.reversed = true;
}
_ => {}
}
Ok(sides)
+5
Переглянути файл
@@ -868,6 +868,11 @@ fn smart_and_force_checkout_with_local_changes_in_the_way() {
assert_eq!(outcome, CheckoutOutcome::Conflicts { files: vec!["f.txt".into()] });
assert_eq!(repo.branch_info().unwrap().head.as_deref(), Some("other"));
assert_eq!(repo.stashes().unwrap().len(), 1, "git keeps the stash after a conflicting pop");
// The stashed edit is the user's side of the merge, the checked-out branch the other.
let v = repo.merge_versions(&fx.path("f.txt")).unwrap();
assert_eq!(v.sides.operation.as_deref(), Some("unstash"));
assert!(v.sides.reversed);
assert_eq!(v.ours.as_deref(), Some("1\nmine\n3\n4\n5\n"));
// Force discards the change in the way.
fx.git(&["reset", "-q", "--hard"]);
+4
Переглянути файл
@@ -71,6 +71,10 @@ describe("mergeTitles", () => {
yours: "Local Changes",
theirs: "Changes from cherry-pick abc12345",
});
expect(mergeTitles(sides("unstash"))).toEqual({
yours: "Your uncommitted changes",
theirs: "Changes from feature",
});
expect(mergeTitles(null)).toEqual({ yours: "Your version", theirs: "Theirs (incoming)" });
});
});
+2
Переглянути файл
@@ -75,6 +75,8 @@ async function performCheckout(rev: string, success: () => string): Promise<bool
const opts = options;
const outcome = await runOp(`Checkout ${rev}`, () => call(commands.vcsCheckout(currentRepo(), rev, false, opts)));
if (!outcome) return false;
// `success` may name the branch now checked out.
if (outcome.kind === "done" || outcome.kind === "conflicts") await refreshNow();
switch (outcome.kind) {
case "done":
notifications().notify({ group: "vcs", level: "info", title: success() });
+5
Переглянути файл
@@ -133,6 +133,11 @@ export function mergeTitles(sides: MergeSides | null | undefined): { yours: stri
yours: branch ? `Changes from ${branch}` : "Your version",
theirs: other ? `Changes from ${other}` : commit ? `Changes from ${commit}` : "Changes from diverging branches",
};
case "unstash":
return {
yours: "Your uncommitted changes",
theirs: branch ? `Changes from ${branch}` : "Changes from remote",
};
case "cherry-pick":
return {
yours: "Local Changes",