mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-13 04:34:21 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66d9306219 |
No files matched your search
@@ -281,6 +281,9 @@ impl Repo {
|
||||
let commitish = arg(commitish, "revision")?;
|
||||
let mut args: Vec<String> = vec!["worktree".into(), "add".into()];
|
||||
if let Some(b) = new_branch.map(str::trim).filter(|b| !b.is_empty()) {
|
||||
if crate::write::renamed_remote_start(self, b, &commitish) {
|
||||
args.push("--no-track".into());
|
||||
}
|
||||
args.extend(["-b".into(), arg(b, "branch name")?]);
|
||||
}
|
||||
args.extend(["--".into(), path, commitish]);
|
||||
|
||||
@@ -800,16 +800,41 @@ pub(crate) fn create_branch(
|
||||
let repo = r.gix()?;
|
||||
resolve(&repo, s)?;
|
||||
}
|
||||
let no_track = start.is_some_and(|s| renamed_remote_start(r, name, s));
|
||||
let mut args = match (checkout, overwrite) {
|
||||
(true, false) => vec!["switch", "-c", name],
|
||||
(true, true) => vec!["switch", "-C", name],
|
||||
(false, false) => vec!["branch", "--", name],
|
||||
(false, true) => vec!["branch", "--force", "--", name],
|
||||
(false, false) => vec!["branch"],
|
||||
(false, true) => vec!["branch", "--force"],
|
||||
};
|
||||
if no_track {
|
||||
args.push("--no-track");
|
||||
}
|
||||
if !checkout {
|
||||
args.extend(["--", name]);
|
||||
}
|
||||
args.extend(start);
|
||||
run(r.root(), &args, None).map(|_| ())
|
||||
}
|
||||
|
||||
/// Whether `start` is a remote-tracking branch with another name than the new branch
|
||||
/// `name`. Git would make it the upstream, so pushing the new branch would go to the
|
||||
/// start branch (`feature` from `origin/main` pushes to `main`); such a branch is left
|
||||
/// without upstream and gets its own one on the first push. A remote branch under the
|
||||
/// same name stays tracked.
|
||||
pub(crate) fn renamed_remote_start(r: &Repo, name: &str, start: &str) -> bool {
|
||||
let Ok(out) = cli::run_raw(r.root(), &["rev-parse", "--verify", "--quiet", "--symbolic-full-name", start], None)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let full = out.stdout_str().trim().to_string();
|
||||
let Some(rest) = full.strip_prefix("refs/remotes/").filter(|_| out.code == Some(0)) else { return false };
|
||||
let Ok(repo) = r.gix() else { return false };
|
||||
let names = repo.remote_names();
|
||||
let branch = names.iter().find_map(|remote| rest.strip_prefix(&format!("{remote}/")));
|
||||
branch.is_some_and(|b| b != name)
|
||||
}
|
||||
|
||||
/// Undo Commit: moves the current branch back to the parent of `commit` (which must be
|
||||
/// HEAD), keeping its changes staged. Returns the undone commit's message.
|
||||
/// Edit Commit Message: writes `commit` again with `message`, and its descendants on top
|
||||
|
||||
@@ -984,15 +984,41 @@ fn branch_overwrite_preserves_the_ref_if_checkout_fails() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_branch_from_remote_branch_tracks_it() {
|
||||
let (fx, _bare) = Fixture::with_origin();
|
||||
fn new_branch_from_remote_branch_tracks_it_only_under_the_same_name() {
|
||||
let (fx, bare) = Fixture::with_origin();
|
||||
fx.git(&["push", "-q", "origin", "main:release"]);
|
||||
fx.git(&["fetch", "-q"]);
|
||||
let repo = fx.repo();
|
||||
let upstream = |name: &str| {
|
||||
repo.branches().unwrap().into_iter().find(|b| b.name == name && !b.remote).and_then(|b| b.upstream)
|
||||
};
|
||||
|
||||
repo.create_branch("release", Some("origin/release"), false).unwrap();
|
||||
assert_eq!(upstream("release").as_deref(), Some("origin/release"));
|
||||
|
||||
// Another name: no upstream, whether switched to or not, created plainly or overwritten.
|
||||
repo.create_branch("other", Some("origin/release"), false).unwrap();
|
||||
assert_eq!(upstream("other"), None);
|
||||
repo.create_branch_with_overwrite("other", Some("origin/main"), false, true).unwrap();
|
||||
assert_eq!(upstream("other"), None);
|
||||
repo.create_branch("my-release", Some("origin/release"), true).unwrap();
|
||||
let info = repo.branch_info().unwrap();
|
||||
assert_eq!(info.head.as_deref(), Some("my-release"));
|
||||
assert_eq!(info.upstream.as_deref(), Some("origin/release"));
|
||||
assert_eq!(info.upstream, None);
|
||||
|
||||
// The first push then goes to a branch of its own name and tracks it.
|
||||
fx.write("a.txt", "mine\n");
|
||||
let tip = fx.commit_all("mine");
|
||||
let (cancel, out) = quiet();
|
||||
repo.push(false, true, &cancel, &out).unwrap();
|
||||
assert_eq!(git_in(&bare, &["rev-parse", "my-release"]), tip);
|
||||
assert_ne!(git_in(&bare, &["rev-parse", "release"]), tip);
|
||||
assert_eq!(fx.git(&["config", "branch.my-release.merge"]), "refs/heads/my-release");
|
||||
|
||||
// New worktree on a new branch from a remote branch: the same rule.
|
||||
let wt = fx.tmp.path().join("wt");
|
||||
repo.add_worktree(&wt, "origin/release", Some("wt-branch")).unwrap();
|
||||
assert_eq!(upstream("wt-branch"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user