mirror of
https://github.com/jj-vcs/jj.git
synced 2025-12-23 06:01:01 +00:00
It would be good to include the word "divergent" in the log when a change is divergent, since users are often unsure what's happening when they see a divergent change, and giving them a term to search for would be helpful. However, I don't think it looks good to put this label next to the change ID itself if both are the same color, since it ends up being hard to distinguish from the change offset at a glance. Also, putting the label next to the change ID also messes up the alignment of fields in the log. Therefore, I think it looks better to put the "divergent" label at the end of the line. Since divergence and hidden commits are similar, it makes sense for both labels to be in the same place, so I also moved the hidden label to the end for consistency. One downside is that the labels are less obviously connected with the change ID itself due to them being farther apart. I think this could be fine, since they are still visually connected by being the same color.
2178 lines
72 KiB
Rust
2178 lines
72 KiB
Rust
// Copyright 2023 The Jujutsu Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use std::io::Write as _;
|
|
|
|
use indoc::indoc;
|
|
use testutils::git;
|
|
|
|
use crate::common::CommandOutput;
|
|
use crate::common::TestEnvironment;
|
|
use crate::common::TestWorkDir;
|
|
use crate::common::create_commit;
|
|
|
|
fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str, message: &str) -> gix::ObjectId {
|
|
// Get current commit ID of the branch if it exists
|
|
let parents = git_repo
|
|
.find_reference(&format!("refs/heads/{branch}"))
|
|
.ok()
|
|
.and_then(|mut r| r.peel_to_commit().ok())
|
|
.map(|c| vec![c.id().detach()])
|
|
.unwrap_or_default();
|
|
|
|
git::add_commit(
|
|
git_repo,
|
|
&format!("refs/heads/{branch}"),
|
|
branch, // filename
|
|
branch.as_bytes(), // content
|
|
message,
|
|
&parents,
|
|
)
|
|
.commit_id
|
|
}
|
|
|
|
/// Creates a remote Git repo containing a bookmark with the same name
|
|
fn init_git_remote(test_env: &TestEnvironment, remote: &str) -> gix::Repository {
|
|
let git_repo_path = test_env.env_root().join(remote);
|
|
let git_repo = git::init(git_repo_path);
|
|
add_commit_to_branch(&git_repo, remote, "message");
|
|
|
|
git_repo
|
|
}
|
|
|
|
/// Add a remote containing a bookmark with the same name
|
|
fn add_git_remote(
|
|
test_env: &TestEnvironment,
|
|
work_dir: &TestWorkDir,
|
|
remote: &str,
|
|
) -> gix::Repository {
|
|
let repo = init_git_remote(test_env, remote);
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", remote, &format!("../{remote}")])
|
|
.success();
|
|
|
|
repo
|
|
}
|
|
|
|
#[must_use]
|
|
fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput {
|
|
// --quiet to suppress deleted bookmarks hint
|
|
work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"])
|
|
}
|
|
|
|
#[must_use]
|
|
fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {
|
|
let template = indoc! {r#"
|
|
separate(" ",
|
|
commit_id.short(),
|
|
'"' ++ description.first_line() ++ '"',
|
|
bookmarks,
|
|
tags,
|
|
) ++ "\n"
|
|
"#};
|
|
work_dir.run_jj(["log", "-T", template, "-r", "all()"])
|
|
}
|
|
|
|
fn clone_git_remote_into(
|
|
test_env: &TestEnvironment,
|
|
upstream: &str,
|
|
fork: &str,
|
|
) -> gix::Repository {
|
|
let upstream_path = test_env.env_root().join(upstream);
|
|
let fork_path = test_env.env_root().join(fork);
|
|
let fork_repo = git::clone(&fork_path, upstream_path.to_str().unwrap(), Some(upstream));
|
|
|
|
// create local branch mirroring the upstream
|
|
let upstream_head = fork_repo
|
|
.find_reference(&format!("refs/remotes/{upstream}/{upstream}"))
|
|
.unwrap()
|
|
.peel_to_id()
|
|
.unwrap()
|
|
.detach();
|
|
|
|
fork_repo
|
|
.reference(
|
|
format!("refs/heads/{upstream}"),
|
|
upstream_head,
|
|
gix::refs::transaction::PreviousValue::MustNotExist,
|
|
"create tracking head",
|
|
)
|
|
.unwrap();
|
|
|
|
fork_repo
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_default_config() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin@origin: qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_default_remote() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_single_remote() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Hint: Fetching from the only existing remote: rem1
|
|
bookmark: rem1@rem1 [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_single_remote_all_remotes_flag() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
|
|
work_dir.run_jj(["git", "fetch", "--all-remotes"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_single_remote_from_arg() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote", "rem1"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_single_remote_from_config() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
test_env.add_config(r#"git.fetch = "rem1""#);
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_multiple_remotes() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
rem2: pzqqpnpo 44c57802 message
|
|
@rem2: pzqqpnpo 44c57802 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_ignored_refspecs() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let source_repo = init_git_remote(&test_env, "origin");
|
|
|
|
for branch in [
|
|
"main", "foo", "foobar", "foobaz", "bar", "sub/yes", "sub/no",
|
|
] {
|
|
add_commit_to_branch(&source_repo, branch, branch);
|
|
}
|
|
|
|
let work_dir = test_env.work_dir("repo");
|
|
std::fs::OpenOptions::new()
|
|
.append(true)
|
|
.open(work_dir.root().join(".jj/repo/store/git/config"))
|
|
.expect("failed to open config file")
|
|
.write_all(
|
|
br#"
|
|
[remote "origin"]
|
|
url = ../origin/.git
|
|
fetch = +refs/heads/main:refs/remotes/origin/main
|
|
fetch = +refs/heads/sub/*:refs/remotes/origin/sub/*
|
|
fetch = +refs/heads/foo*:refs/remotes/origin/baz*
|
|
fetch = +refs/heads/bar*:refs/tags/bar*
|
|
fetch = refs/heads/bar
|
|
fetch = ^refs/heads/sub/no
|
|
"#,
|
|
)
|
|
.expect("failed to update config file");
|
|
|
|
// Should fetch "main" and "sub/yes" by default
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported
|
|
Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations
|
|
Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported
|
|
bookmark: main@origin [new] untracked
|
|
bookmark: sub/yes@origin [new] untracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
main@origin: wlltxvop a437242b main
|
|
sub/yes@origin: xwxtqxvy 6b64b005 sub/yes
|
|
[EOF]
|
|
");
|
|
|
|
// Can fetch ignored "sub/no" explicitly
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch=sub/no"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: sub/no@origin [new] untracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
main@origin: wlltxvop a437242b main
|
|
sub/no@origin: tknwmolt f7d8b914 sub/no
|
|
sub/yes@origin: xwxtqxvy 6b64b005 sub/yes
|
|
[EOF]
|
|
");
|
|
|
|
// Forget "sub/no" without exporting the change to Git
|
|
work_dir
|
|
.run_jj(["bookmark", "forget", "--include-remotes", "sub/no"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
main@origin: wlltxvop a437242b main
|
|
sub/yes@origin: xwxtqxvy 6b64b005 sub/yes
|
|
[EOF]
|
|
");
|
|
|
|
// Should not import "sub/no" because it is ignored by default
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported
|
|
Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations
|
|
Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
main@origin: wlltxvop a437242b main
|
|
sub/yes@origin: xwxtqxvy 6b64b005 sub/yes
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_glob() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote", "*"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: rem1@rem1 [new] untracked
|
|
bookmark: rem2@rem2 [new] untracked
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_glob_and_exact_match() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
add_git_remote(&test_env, &work_dir, "upstream1");
|
|
add_git_remote(&test_env, &work_dir, "upstream2");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote=rem*", "--remote=origin"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: origin@origin [new] untracked
|
|
bookmark: rem1@rem1 [new] untracked
|
|
bookmark: rem2@rem2 [new] untracked
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_glob_from_config() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config(r#"git.fetch = "rem*""#);
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
add_git_remote(&test_env, &work_dir, "upstream");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: rem1@rem1 [new] untracked
|
|
bookmark: rem2@rem2 [new] untracked
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_with_glob_with_no_matching_remotes() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "upstream");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote=rem*"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: No git remotes to fetch from
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
// No remote should have been fetched as part of the failing transaction
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_all_remotes() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
|
|
// add empty [remote "rem3"] section to .git/config, which should be ignored
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "rem3", "../unknown"])
|
|
.success();
|
|
work_dir
|
|
.run_jj(["git", "remote", "remove", "rem3"])
|
|
.success();
|
|
|
|
work_dir.run_jj(["git", "fetch", "--all-remotes"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
rem2: pzqqpnpo 44c57802 message
|
|
@rem2: pzqqpnpo 44c57802 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_multiple_remotes_from_config() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#);
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
rem2: pzqqpnpo 44c57802 message
|
|
@rem2: pzqqpnpo 44c57802 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_no_matching_remote() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching remotes for names: rem1
|
|
Error: No git remotes to fetch from
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote=rem1", "--remote=rem2"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching remotes for names: rem1, rem2
|
|
Error: No git remotes to fetch from
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_nonexistent_remote() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching remotes for names: rem2
|
|
bookmark: rem1@rem1 [new] untracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_nonexistent_remote_from_config() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#);
|
|
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching remotes for names: rem2
|
|
bookmark: rem1@rem1 [new] untracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1@rem1: ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_from_remote_named_git() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.bar.auto-track-bookmarks = '*'");
|
|
let work_dir = test_env.work_dir("repo");
|
|
init_git_remote(&test_env, "git");
|
|
|
|
git::init(work_dir.root());
|
|
git::add_remote(work_dir.root(), "git", "../git");
|
|
|
|
// Existing remote named 'git' shouldn't block the repo initialization.
|
|
work_dir.run_jj(["git", "init", "--git-repo=."]).success();
|
|
|
|
// Try fetching from the remote named 'git'.
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote=git"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Git remote named 'git' is reserved for local Git repository
|
|
Hint: Run `jj git remote rename` to give a different name.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Fetch remote refs by using the git CLI.
|
|
git::fetch(work_dir.root(), "git");
|
|
|
|
// Implicit import shouldn't fail because of the remote ref.
|
|
let output = work_dir.run_jj(["bookmark", "list", "--all-remotes"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: Failed to import some Git refs:
|
|
refs/remotes/git/git
|
|
Hint: Git remote named 'git' is reserved for local Git repository.
|
|
Use `jj git remote rename` to give a different name.
|
|
[EOF]
|
|
");
|
|
|
|
// Explicit import also works. Warnings are printed twice because this is a
|
|
// colocated workspace. That should be fine since "jj git import" wouldn't
|
|
// be used in colocated environment.
|
|
insta::assert_snapshot!(work_dir.run_jj(["git", "import"]), @r"
|
|
------- stderr -------
|
|
Warning: Failed to import some Git refs:
|
|
refs/remotes/git/git
|
|
Hint: Git remote named 'git' is reserved for local Git repository.
|
|
Use `jj git remote rename` to give a different name.
|
|
Warning: Failed to import some Git refs:
|
|
refs/remotes/git/git
|
|
Hint: Git remote named 'git' is reserved for local Git repository.
|
|
Use `jj git remote rename` to give a different name.
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
|
|
// The remote can be renamed, and the ref can be imported.
|
|
work_dir
|
|
.run_jj(["git", "remote", "rename", "git", "bar"])
|
|
.success();
|
|
let output = work_dir.run_jj(["bookmark", "list", "--all-remotes"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
git: vkponlun 400c483d message
|
|
@bar: vkponlun 400c483d message
|
|
@git: vkponlun 400c483d message
|
|
[EOF]
|
|
------- stderr -------
|
|
Done importing changes from the underlying Git repo.
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_from_remote_with_slashes() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
let work_dir = test_env.work_dir("repo");
|
|
init_git_remote(&test_env, "source");
|
|
|
|
git::init(work_dir.root());
|
|
git::add_remote(work_dir.root(), "slash/origin", "../source");
|
|
|
|
// Existing remote with slash shouldn't block the repo initialization.
|
|
work_dir.run_jj(["git", "init", "--git-repo=."]).success();
|
|
|
|
// Try fetching from the remote named 'git'.
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote=slash/origin"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Git remotes with slashes are incompatible with jj: slash/origin
|
|
Hint: Run `jj git remote rename` to give a different name.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_prune_before_updating_tips() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
let git_repo = add_git_remote(&test_env, &work_dir, "origin");
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
// Remove origin bookmark in git repo and create origin/subname
|
|
let mut origin_reference = git_repo.find_reference("refs/heads/origin").unwrap();
|
|
let commit_id = origin_reference.peel_to_commit().unwrap().id().detach();
|
|
origin_reference.delete().unwrap();
|
|
git_repo
|
|
.reference(
|
|
"refs/heads/origin/subname",
|
|
commit_id,
|
|
gix::refs::transaction::PreviousValue::MustNotExist,
|
|
"create new reference",
|
|
)
|
|
.unwrap();
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin/subname: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_conflicting_bookmarks() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
|
|
// Create a rem1 bookmark locally
|
|
work_dir.run_jj(["new", "root()"]).success();
|
|
work_dir
|
|
.run_jj(["bookmark", "create", "-r@", "rem1"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: kkmpptxz 2b17ac71 (empty) (no description set)
|
|
@rem1 (not created yet)
|
|
[EOF]
|
|
");
|
|
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote", "rem1", "--branch", "*"])
|
|
.success();
|
|
// This should result in a CONFLICTED bookmark
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1 (conflicted):
|
|
+ kkmpptxz 2b17ac71 (empty) (no description set)
|
|
+ ppspxspk 4acd0343 message
|
|
@rem1 (behind by 1 commits): ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_conflicting_bookmarks_colocated() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
let work_dir = test_env.work_dir("repo");
|
|
git::init(work_dir.root());
|
|
// create_colocated_repo_and_bookmarks_from_trunk1(&test_env, &repo_path);
|
|
work_dir
|
|
.run_jj(["git", "init", "--git-repo", "."])
|
|
.success();
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
|
|
// Create a rem1 bookmark locally
|
|
work_dir.run_jj(["new", "root()"]).success();
|
|
work_dir
|
|
.run_jj(["bookmark", "create", "-r@", "rem1"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1: zsuskuln c2934cfb (empty) (no description set)
|
|
@git: zsuskuln c2934cfb (empty) (no description set)
|
|
@rem1 (not created yet)
|
|
[EOF]
|
|
");
|
|
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote", "rem1", "--branch", "rem1"])
|
|
.success();
|
|
// This should result in a CONFLICTED bookmark
|
|
// See https://github.com/jj-vcs/jj/pull/1146#discussion_r1112372340 for the bug this tests for.
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
rem1 (conflicted):
|
|
+ zsuskuln c2934cfb (empty) (no description set)
|
|
+ ppspxspk 4acd0343 message
|
|
@git (behind by 1 commits): zsuskuln c2934cfb (empty) (no description set)
|
|
@rem1 (behind by 1 commits): ppspxspk 4acd0343 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
// Helper functions to test obtaining multiple bookmarks at once and changed
|
|
// bookmarks
|
|
fn create_colocated_repo_and_bookmarks_from_trunk1(work_dir: &TestWorkDir) -> String {
|
|
// Create a colocated workspace in `source` to populate it more easily
|
|
work_dir
|
|
.run_jj(["git", "init", "--git-repo", "."])
|
|
.success();
|
|
create_commit(work_dir, "trunk1", &[]);
|
|
create_commit(work_dir, "a1", &["trunk1"]);
|
|
create_commit(work_dir, "a2", &["trunk1"]);
|
|
create_commit(work_dir, "b", &["trunk1"]);
|
|
format!(
|
|
" ===== Source git repo contents =====\n{}",
|
|
get_log_output(work_dir)
|
|
)
|
|
}
|
|
|
|
fn create_trunk2_and_rebase_bookmarks(work_dir: &TestWorkDir) -> String {
|
|
create_commit(work_dir, "trunk2", &["trunk1"]);
|
|
for br in ["a1", "a2", "b"] {
|
|
work_dir
|
|
.run_jj(["rebase", "-b", br, "-o", "trunk2"])
|
|
.success();
|
|
}
|
|
format!(
|
|
" ===== Source git repo contents =====\n{}",
|
|
get_log_output(work_dir)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_all() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let target_dir = test_env.work_dir("target");
|
|
|
|
let source_log = create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Nothing in our repo before the fetch
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @"");
|
|
let output = target_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [new] tracked
|
|
bookmark: a2@origin [new] tracked
|
|
bookmark: b@origin [new] tracked
|
|
bookmark: trunk1@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
a1: mzvwutvl c8303692 a1
|
|
@origin: mzvwutvl c8303692 a1
|
|
a2: yqosqzyt d4d535f1 a2
|
|
@origin: yqosqzyt d4d535f1 a2
|
|
b: yostqsxw bc83465a b
|
|
@origin: yostqsxw bc83465a b
|
|
trunk1: kkmpptxz 38288177 trunk1
|
|
@origin: kkmpptxz 38288177 trunk1
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// ==== Change both repos ====
|
|
// First, change the target repo:
|
|
let source_log = create_trunk2_and_rebase_bookmarks(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
○ 6fc6fe17dbee "b" b
|
|
│ ○ baad96fead6c "a2" a2
|
|
├─╯
|
|
│ ○ 798c5e2435e1 "a1" a1
|
|
├─╯
|
|
@ e80d998ab04b "trunk2" trunk2
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// Change a bookmark in the source repo as well, so that it becomes conflicted.
|
|
target_dir
|
|
.run_jj(["describe", "b", "-m=new_descr_for_b_to_create_conflict"])
|
|
.success();
|
|
|
|
// Our repo before and after fetch
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ 0fbbc495357c "new_descr_for_b_to_create_conflict" b*
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
a1: mzvwutvl c8303692 a1
|
|
@origin: mzvwutvl c8303692 a1
|
|
a2: yqosqzyt d4d535f1 a2
|
|
@origin: yqosqzyt d4d535f1 a2
|
|
b: yostqsxw 0fbbc495 new_descr_for_b_to_create_conflict
|
|
@origin (ahead by 1 commits, behind by 1 commits): yostqsxw/1 bc83465a (hidden) b
|
|
trunk1: kkmpptxz 38288177 trunk1
|
|
@origin: kkmpptxz 38288177 trunk1
|
|
[EOF]
|
|
");
|
|
let output = target_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [updated] tracked
|
|
bookmark: a2@origin [updated] tracked
|
|
bookmark: b@origin [updated] tracked
|
|
bookmark: trunk2@origin [new] tracked
|
|
Abandoned 2 commits that are no longer reachable.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
a1: mzvwutvl 798c5e24 a1
|
|
@origin: mzvwutvl 798c5e24 a1
|
|
a2: yqosqzyt baad96fe a2
|
|
@origin: yqosqzyt baad96fe a2
|
|
b (conflicted):
|
|
- yostqsxw/2 bc83465a (hidden) b
|
|
+ yostqsxw/1 0fbbc495 (divergent) new_descr_for_b_to_create_conflict
|
|
+ yostqsxw/0 6fc6fe17 (divergent) b
|
|
@origin (behind by 1 commits): yostqsxw/0 6fc6fe17 (divergent) b
|
|
trunk1: kkmpptxz 38288177 trunk1
|
|
@origin: kkmpptxz 38288177 trunk1
|
|
trunk2: uyznsvlq e80d998a trunk2
|
|
@origin: uyznsvlq e80d998a trunk2
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ 6fc6fe17dbee "b" b?? b@origin
|
|
│ │ ○ baad96fead6c "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ 798c5e2435e1 "a1" a1
|
|
│ ├─╯
|
|
│ ○ e80d998ab04b "trunk2" trunk2
|
|
│ │ ○ 0fbbc495357c "new_descr_for_b_to_create_conflict" b??
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_some_of_many_bookmarks() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let target_dir = test_env.work_dir("target");
|
|
|
|
let source_log = create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Test an error message
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "'^:a*'"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Invalid branch pattern provided. When fetching, branch names and globs may not contain the characters `:`, `^`, `?`, `[`, `]`
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "exact:a*"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Invalid branch pattern provided. When fetching, branch names and globs may not contain the characters `:`, `^`, `?`, `[`, `]`
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Nothing in our repo before the fetch
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// Fetch one bookmark...
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "b"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: b@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// ...check what the intermediate state looks like...
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
b: yostqsxw bc83465a b
|
|
@origin: yostqsxw bc83465a b
|
|
[EOF]
|
|
");
|
|
// ...then fetch two others with a glob.
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "a*"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [new] tracked
|
|
bookmark: a2@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ │ ○ bc83465a3090 "b" b
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// Fetching the same bookmark again
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "a1"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ │ ○ bc83465a3090 "b" b
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// ==== Change both repos ====
|
|
// First, change the target repo:
|
|
let source_log = create_trunk2_and_rebase_bookmarks(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
○ 2b30dbc93959 "b" b
|
|
│ ○ 841140b152fc "a2" a2
|
|
├─╯
|
|
│ ○ bc7e74c21d43 "a1" a1
|
|
├─╯
|
|
@ 756be1d31c41 "trunk2" trunk2
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// Change a bookmark in the source repo as well, so that it becomes conflicted.
|
|
target_dir
|
|
.run_jj(["describe", "b", "-m=new_descr_for_b_to_create_conflict"])
|
|
.success();
|
|
|
|
// Our repo before and after fetch of two bookmarks
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ c62db3119722 "new_descr_for_b_to_create_conflict" b*
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch=~(a2 | trunk*)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [updated] tracked
|
|
bookmark: b@origin [updated] tracked
|
|
Abandoned 1 commits that are no longer reachable.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ 2b30dbc93959 "b" b?? b@origin
|
|
│ │ ○ bc7e74c21d43 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 756be1d31c41 "trunk2"
|
|
│ │ ○ c62db3119722 "new_descr_for_b_to_create_conflict" b??
|
|
│ ├─╯
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// We left a2 where it was before, let's see how `jj bookmark list` sees this.
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
a1: mzvwutvl bc7e74c2 a1
|
|
@origin: mzvwutvl bc7e74c2 a1
|
|
a2: yqosqzyt d4d535f1 a2
|
|
@origin: yqosqzyt d4d535f1 a2
|
|
b (conflicted):
|
|
- yostqsxw/2 bc83465a (hidden) b
|
|
+ yostqsxw/1 c62db311 (divergent) new_descr_for_b_to_create_conflict
|
|
+ yostqsxw/0 2b30dbc9 (divergent) b
|
|
@origin (behind by 1 commits): yostqsxw/0 2b30dbc9 (divergent) b
|
|
[EOF]
|
|
");
|
|
// Now, let's fetch a2 and double-check that fetching a1 and b again doesn't do
|
|
// anything.
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "b", "--branch", "a*"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a2@origin [updated] tracked
|
|
Abandoned 1 commits that are no longer reachable.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ 841140b152fc "a2" a2
|
|
│ │ ○ 2b30dbc93959 "b" b?? b@origin
|
|
│ ├─╯
|
|
│ │ ○ bc7e74c21d43 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 756be1d31c41 "trunk2"
|
|
│ │ ○ c62db3119722 "new_descr_for_b_to_create_conflict" b??
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&target_dir), @r"
|
|
a1: mzvwutvl bc7e74c2 a1
|
|
@origin: mzvwutvl bc7e74c2 a1
|
|
a2: yqosqzyt 841140b1 a2
|
|
@origin: yqosqzyt 841140b1 a2
|
|
b (conflicted):
|
|
- yostqsxw/2 bc83465a (hidden) b
|
|
+ yostqsxw/1 c62db311 (divergent) new_descr_for_b_to_create_conflict
|
|
+ yostqsxw/0 2b30dbc9 (divergent) b
|
|
@origin (behind by 1 commits): yostqsxw/0 2b30dbc9 (divergent) b
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_bookmarks_some_missing() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.rem3.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
add_git_remote(&test_env, &work_dir, "rem1");
|
|
add_git_remote(&test_env, &work_dir, "rem2");
|
|
add_git_remote(&test_env, &work_dir, "rem3");
|
|
|
|
// single missing bookmark, implicit remotes (@origin)
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch", "noexist"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching branches found on any specified/configured remote: noexist
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
|
|
// multiple missing bookmarks, implicit remotes (@origin)
|
|
let output = work_dir.run_jj([
|
|
"git", "fetch", "--branch", "noexist1", "--branch", "noexist2",
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching branches found on any specified/configured remote: noexist1, noexist2
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
|
|
// single existing bookmark, implicit remotes (@origin)
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch", "origin"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: origin@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
// multiple existing bookmark, explicit remotes, each bookmark is only in one
|
|
// remote.
|
|
let output = work_dir.run_jj([
|
|
"git", "fetch", "--branch", "rem1", "--branch", "rem2", "--branch", "rem3", "--remote",
|
|
"rem1", "--remote", "rem2", "--remote", "rem3",
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: rem1@rem1 [new] tracked
|
|
bookmark: rem2@rem2 [new] tracked
|
|
bookmark: rem3@rem3 [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
rem2: pzqqpnpo 44c57802 message
|
|
@rem2: pzqqpnpo 44c57802 message
|
|
rem3: wrzwlmys 45a3faef message
|
|
@rem3: wrzwlmys 45a3faef message
|
|
[EOF]
|
|
");
|
|
|
|
// multiple bookmarks, one exists, one doesn't
|
|
let output = work_dir.run_jj([
|
|
"git", "fetch", "--branch", "rem1", "--branch", "notexist", "--remote", "rem1",
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching branches found on any specified/configured remote: notexist
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qmyrypzk ab8b299e message
|
|
@origin: qmyrypzk ab8b299e message
|
|
rem1: ppspxspk 4acd0343 message
|
|
@rem1: ppspxspk 4acd0343 message
|
|
rem2: pzqqpnpo 44c57802 message
|
|
@rem2: pzqqpnpo 44c57802 message
|
|
rem3: wrzwlmys 45a3faef message
|
|
@rem3: wrzwlmys 45a3faef message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_bookmarks_missing_with_subprocess_localized_message() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
// "fatal: couldn't find remote ref %s" shouldn't be localized.
|
|
let output = work_dir.run_jj_with(|cmd| {
|
|
cmd.args(["git", "fetch", "--branch=unknown"])
|
|
// Initialize locale as "en_US" which is the most common.
|
|
.env("LC_ALL", "en_US.UTF-8")
|
|
// Set some other locale variables for testing.
|
|
.env("LC_MESSAGES", "en_US.UTF-8")
|
|
.env("LANG", "en_US.UTF-8")
|
|
// GNU gettext prioritizes LANGUAGE if translation is enabled. It works
|
|
// no matter if system locale exists or not.
|
|
.env("LANGUAGE", "zh_TW")
|
|
});
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Warning: No matching branches found on any specified/configured remote: unknown
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_unsupported_branch_patterns() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch=x&y|z"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Cannot use `&` in sub expression
|
|
Hint: Specify patterns in `(positive | ...) & ~(negative | ...)` form.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Unsupported glob pattern in negative refspecs
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch=~'[xy]'"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Invalid branch pattern provided. When fetching, branch names and globs may not contain the characters `:`, `^`, `?`, `[`, `]`
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
// See `test_undo_restore_commands.rs` for fetch-undo-push and fetch-undo-fetch
|
|
// of the same bookmarks for various kinds of undo.
|
|
#[test]
|
|
fn test_git_fetch_undo() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let target_dir = test_env.work_dir("target");
|
|
|
|
create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
source_dir
|
|
.run_jj(["tag", "set", "-rtrunk1", "tag1"])
|
|
.success();
|
|
insta::assert_snapshot!(get_log_output(&source_dir), @r#"
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
◆ 382881770501 "trunk1" trunk1 tag1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Fetch 2 bookmarks and tags
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "b", "--branch", "a1"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [new] tracked
|
|
bookmark: b@origin [new] tracked
|
|
tag: tag1@git [new]
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ◆ 382881770501 "trunk1" tag1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
let output = target_dir.run_jj(["undo"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Restored to operation: 8aeac520a856 (2001-02-03 08:05:07) add git remote origin
|
|
[EOF]
|
|
");
|
|
// The undo works as expected
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
// Now try to fetch just one bookmark and tags
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "b"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: b@origin [new] tracked
|
|
tag: tag1@git [new]
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ ◆ 382881770501 "trunk1" tag1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
}
|
|
|
|
// Compare to `test_git_import_undo` in test_git_import_export
|
|
// TODO: Explain why these behaviors are useful
|
|
#[test]
|
|
fn test_fetch_undo_what() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let work_dir = test_env.work_dir("target");
|
|
|
|
let source_log = create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Initial state we will try to return to after `op restore`. There are no
|
|
// bookmarks.
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
|
let base_operation_id = work_dir.current_operation_id();
|
|
|
|
// Fetch a bookmark
|
|
let output = work_dir.run_jj(["git", "fetch", "--branch", "b"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: b@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&work_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
b: yostqsxw bc83465a b
|
|
@origin: yostqsxw bc83465a b
|
|
[EOF]
|
|
");
|
|
|
|
// We can undo the change in the repo without moving the remote-tracking
|
|
// bookmark
|
|
let output = work_dir.run_jj(["op", "restore", "--what", "repo", &base_operation_id]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Restored to operation: 8aeac520a856 (2001-02-03 08:05:07) add git remote origin
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
b (deleted)
|
|
@origin: yostqsxw/0 bc83465a (hidden) b
|
|
[EOF]
|
|
");
|
|
|
|
// Now, let's demo restoring just the remote-tracking bookmark. First, let's
|
|
// change our local repo state...
|
|
work_dir
|
|
.run_jj(["bookmark", "c", "-r@", "newbookmark"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
b (deleted)
|
|
@origin: yostqsxw/0 bc83465a (hidden) b
|
|
newbookmark: qpvuntsm e8849ae1 (empty) (no description set)
|
|
@origin (not created yet)
|
|
[EOF]
|
|
");
|
|
// Restoring just the remote-tracking state will not affect `newbookmark`, but
|
|
// will eliminate `b@origin`.
|
|
let output = work_dir.run_jj([
|
|
"op",
|
|
"restore",
|
|
"--what",
|
|
"remote-tracking",
|
|
&base_operation_id,
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Restored to operation: 8aeac520a856 (2001-02-03 08:05:07) add git remote origin
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
newbookmark: qpvuntsm e8849ae1 (empty) (no description set)
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_remove_fetch() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
work_dir
|
|
.run_jj(["bookmark", "create", "-r@", "origin"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qpvuntsm e8849ae1 (empty) (no description set)
|
|
@origin (not created yet)
|
|
[EOF]
|
|
");
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin (conflicted):
|
|
+ qpvuntsm e8849ae1 (empty) (no description set)
|
|
+ qmyrypzk ab8b299e message
|
|
@origin (behind by 1 commits): qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
work_dir
|
|
.run_jj(["git", "remote", "remove", "origin"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin (conflicted):
|
|
+ qpvuntsm e8849ae1 (empty) (no description set)
|
|
+ qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../origin"])
|
|
.success();
|
|
|
|
// Check that origin@origin is properly recreated
|
|
let output = work_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: origin@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin (conflicted):
|
|
+ qpvuntsm e8849ae1 (empty) (no description set)
|
|
+ qmyrypzk ab8b299e message
|
|
@origin (behind by 1 commits): qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_rename_fetch() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
add_git_remote(&test_env, &work_dir, "origin");
|
|
|
|
work_dir
|
|
.run_jj(["bookmark", "create", "-r@", "origin"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin: qpvuntsm e8849ae1 (empty) (no description set)
|
|
@origin (not created yet)
|
|
[EOF]
|
|
");
|
|
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin (conflicted):
|
|
+ qpvuntsm e8849ae1 (empty) (no description set)
|
|
+ qmyrypzk ab8b299e message
|
|
@origin (behind by 1 commits): qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
work_dir
|
|
.run_jj(["git", "remote", "rename", "origin", "upstream"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
origin (conflicted):
|
|
+ qpvuntsm e8849ae1 (empty) (no description set)
|
|
+ qmyrypzk ab8b299e message
|
|
@upstream (behind by 1 commits): qmyrypzk ab8b299e message
|
|
[EOF]
|
|
");
|
|
|
|
// Check that jj indicates that nothing has changed
|
|
let output = work_dir.run_jj(["git", "fetch", "--remote", "upstream"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_removed_bookmark() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let target_dir = test_env.work_dir("target");
|
|
|
|
let source_log = create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Fetch all bookmarks
|
|
let output = target_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [new] tracked
|
|
bookmark: a2@origin [new] tracked
|
|
bookmark: b@origin [new] tracked
|
|
bookmark: trunk1@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Remove a2 bookmark in origin
|
|
source_dir
|
|
.run_jj(["bookmark", "forget", "--include-remotes", "a2"])
|
|
.success();
|
|
|
|
// Fetch bookmark a1 from origin and check that a2 is still there
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "a1"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Fetch bookmarks a2 from origin, and check that it has been removed locally
|
|
let output = target_dir.run_jj(["git", "fetch", "--branch", "a2"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a2@origin [deleted] untracked
|
|
Abandoned 1 commits that are no longer reachable.
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_removed_parent_bookmark() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
let source_dir = test_env.work_dir("source");
|
|
git::init(source_dir.root());
|
|
|
|
// Clone an empty repo. The target repo is a normal `jj` repo, *not* colocated
|
|
let output = test_env.run_jj_in(".", ["git", "clone", "source", "target"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Fetching into new repo in "$TEST_ENV/target"
|
|
Nothing changed.
|
|
[EOF]
|
|
"#);
|
|
let target_dir = test_env.work_dir("target");
|
|
|
|
let source_log = create_colocated_repo_and_bookmarks_from_trunk1(&source_dir);
|
|
insta::assert_snapshot!(source_log, @r#"
|
|
===== Source git repo contents =====
|
|
@ bc83465a3090 "b" b
|
|
│ ○ d4d535f1d579 "a2" a2
|
|
├─╯
|
|
│ ○ c8303692b8e2 "a1" a1
|
|
├─╯
|
|
○ 382881770501 "trunk1" trunk1
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Fetch all bookmarks
|
|
let output = target_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [new] tracked
|
|
bookmark: a2@origin [new] tracked
|
|
bookmark: b@origin [new] tracked
|
|
bookmark: trunk1@origin [new] tracked
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ │ ○ c8303692b8e2 "a1" a1
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1" trunk1
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
|
|
// Remove all bookmarks in origin.
|
|
source_dir
|
|
.run_jj(["bookmark", "forget", "--include-remotes", "*"])
|
|
.success();
|
|
|
|
// Fetch bookmarks master, trunk1 and a1 from origin and check that only those
|
|
// bookmarks have been removed and that others were not rebased because of
|
|
// abandoned commits.
|
|
let output = target_dir.run_jj([
|
|
"git", "fetch", "--branch", "master", "--branch", "trunk1", "--branch", "a1",
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: a1@origin [deleted] untracked
|
|
bookmark: trunk1@origin [deleted] untracked
|
|
Abandoned 1 commits that are no longer reachable.
|
|
Warning: No matching branches found on any specified/configured remote: master
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(get_log_output(&target_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bc83465a3090 "b" b
|
|
│ │ ○ d4d535f1d579 "a2" a2
|
|
│ ├─╯
|
|
│ ○ 382881770501 "trunk1"
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_remote_only_bookmark() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
// Create non-empty git repo to add as a remote
|
|
let git_repo_path = test_env.env_root().join("git-repo");
|
|
let git_repo = git::init(git_repo_path);
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../git-repo"])
|
|
.success();
|
|
|
|
// Create a commit and a bookmark in the git repo
|
|
let commit_result = git::add_commit(
|
|
&git_repo,
|
|
"refs/heads/feature1",
|
|
"file",
|
|
b"content",
|
|
"message",
|
|
&[],
|
|
);
|
|
|
|
// Fetch using remotes.origin.auto-track-bookmarks = '*'
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote=origin"])
|
|
.success();
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: qomsplrm ebeb70d8 message
|
|
@origin: qomsplrm ebeb70d8 message
|
|
[EOF]
|
|
");
|
|
|
|
git::write_commit(
|
|
&git_repo,
|
|
"refs/heads/feature2",
|
|
commit_result.tree_id,
|
|
"message",
|
|
&[],
|
|
);
|
|
|
|
// Fetch using remotes.origin.auto-track-bookmarks = '~*'
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '~*'");
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote=origin"])
|
|
.success();
|
|
insta::assert_snapshot!(get_log_output(&work_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ◆ ebeb70d8c5f9 "message" feature1 feature2@origin
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: qomsplrm ebeb70d8 message
|
|
@origin: qomsplrm ebeb70d8 message
|
|
feature2@origin: qomsplrm ebeb70d8 message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_preserve_commits_across_repos() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.upstream.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.fork.auto-track-bookmarks = '*'");
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
let upstream_repo = add_git_remote(&test_env, &work_dir, "upstream");
|
|
|
|
let fork_path = test_env.env_root().join("fork");
|
|
let fork_repo = clone_git_remote_into(&test_env, "upstream", "fork");
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "fork", "../fork"])
|
|
.success();
|
|
|
|
// add commit to fork remote in another branch
|
|
add_commit_to_branch(&fork_repo, "feature", "message");
|
|
|
|
// fetch remote bookmarks
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote=fork", "--remote=upstream"])
|
|
.success();
|
|
insta::assert_snapshot!(get_log_output(&work_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ bcd7cd779791 "message" upstream
|
|
├─╯
|
|
│ ○ 16ec9ef2877a "message" feature
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature: srwrtuky 16ec9ef2 message
|
|
@fork: srwrtuky 16ec9ef2 message
|
|
upstream: zkvzklqn bcd7cd77 message
|
|
@fork: zkvzklqn bcd7cd77 message
|
|
@upstream: zkvzklqn bcd7cd77 message
|
|
[EOF]
|
|
");
|
|
|
|
// merge fork/feature into the upstream/upstream
|
|
git::add_remote(upstream_repo.git_dir(), "fork", fork_path.to_str().unwrap());
|
|
git::fetch(upstream_repo.git_dir(), "fork");
|
|
|
|
let base_id = upstream_repo
|
|
.find_reference("refs/heads/upstream")
|
|
.unwrap()
|
|
.peel_to_commit()
|
|
.unwrap()
|
|
.id()
|
|
.detach();
|
|
|
|
let fork_id = upstream_repo
|
|
.find_reference("refs/remotes/fork/feature")
|
|
.unwrap()
|
|
.peel_to_commit()
|
|
.unwrap()
|
|
.id()
|
|
.detach();
|
|
|
|
git::write_commit(
|
|
&upstream_repo,
|
|
"refs/heads/upstream",
|
|
upstream_repo.empty_tree().id().detach(),
|
|
"merge",
|
|
&[base_id, fork_id],
|
|
);
|
|
|
|
// remove branch on the fork
|
|
fork_repo
|
|
.find_reference("refs/heads/feature")
|
|
.unwrap()
|
|
.delete()
|
|
.unwrap();
|
|
|
|
// fetch again on the jj repo, first looking at fork and then at upstream
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--remote=fork", "--remote=upstream"])
|
|
.success();
|
|
insta::assert_snapshot!(get_log_output(&work_dir), @r#"
|
|
@ e8849ae12c70 ""
|
|
│ ○ f3e9250bd003 "merge" upstream*
|
|
│ ├─╮
|
|
│ │ ○ 16ec9ef2877a "message"
|
|
├───╯
|
|
│ ○ bcd7cd779791 "message" upstream@fork
|
|
├─╯
|
|
◆ 000000000000 ""
|
|
[EOF]
|
|
"#);
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
upstream: trrkvuqr f3e9250b merge
|
|
@fork (behind by 2 commits): zkvzklqn bcd7cd77 message
|
|
@upstream: trrkvuqr f3e9250b merge
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_tracked() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
|
|
// Set up a remote with multiple bookmarks
|
|
let remote_path = test_env.env_root().join("remote");
|
|
let remote_repo = git::init(remote_path.clone());
|
|
add_commit_to_branch(&remote_repo, "main", "message");
|
|
add_commit_to_branch(&remote_repo, "feature1", "message");
|
|
add_commit_to_branch(&remote_repo, "feature2", "message");
|
|
|
|
// Initialize jj repo
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
// Add the remote to the jj repo
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../remote"])
|
|
.success();
|
|
|
|
// Initially fetch only main and feature1
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--branch", "main", "--branch", "feature1"])
|
|
.success();
|
|
|
|
// Both should be tracked
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: txqvqkwm fc8f3f42 message
|
|
@origin: txqvqkwm fc8f3f42 message
|
|
main: kmpysrkw 0130f303 message
|
|
@origin: kmpysrkw 0130f303 message
|
|
[EOF]
|
|
");
|
|
|
|
// Now untrack feature1
|
|
work_dir
|
|
.run_jj(["bookmark", "untrack", "feature1"])
|
|
.success();
|
|
|
|
// Verify feature1 is untracked
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: txqvqkwm fc8f3f42 message
|
|
feature1@origin: txqvqkwm fc8f3f42 message
|
|
main: kmpysrkw 0130f303 message
|
|
@origin: kmpysrkw 0130f303 message
|
|
[EOF]
|
|
");
|
|
|
|
// Add new commits to all bookmarks on the remote
|
|
add_commit_to_branch(&remote_repo, "main", "message");
|
|
add_commit_to_branch(&remote_repo, "feature1", "message");
|
|
add_commit_to_branch(&remote_repo, "feature2", "message");
|
|
|
|
// Fetch with --tracked should only update main (which is still tracked)
|
|
work_dir.run_jj(["git", "fetch", "--tracked"]).success();
|
|
|
|
// Main should be updated to the new commit, but feature1 should remain
|
|
// unchanged
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: txqvqkwm fc8f3f42 message
|
|
feature1@origin: txqvqkwm fc8f3f42 message
|
|
main: kmktnoqm 381bf13c (empty) message
|
|
@origin: kmktnoqm 381bf13c (empty) message
|
|
[EOF]
|
|
");
|
|
|
|
// Now fetch all branches
|
|
work_dir.run_jj(["git", "fetch", "--branch", "*"]).success();
|
|
|
|
// Now feature1@origin gets updated but feature1 stays at old commit
|
|
// (untracked), feature2 appears for the first time, and main stays at its
|
|
// already-updated commit
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
feature1: txqvqkwm fc8f3f42 message
|
|
feature1@origin: ksswsvzv 0c0873bb (empty) message
|
|
feature2: ruyplonr 13e64e92 (empty) message
|
|
@origin: ruyplonr 13e64e92 (empty) message
|
|
main: kmktnoqm 381bf13c (empty) message
|
|
@origin: kmktnoqm 381bf13c (empty) message
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_tracked_no_tracked_bookmarks() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
|
|
// Set up a remote with bookmarks
|
|
let remote_path = test_env.env_root().join("remote");
|
|
let remote_repo = git::init(remote_path.clone());
|
|
add_commit_to_branch(&remote_repo, "main", "message");
|
|
add_commit_to_branch(&remote_repo, "feature", "message");
|
|
|
|
// Initialize jj repo
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
// Add the remote to the jj repo
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../remote"])
|
|
.success();
|
|
|
|
// Initially fetch bookmarks
|
|
work_dir.run_jj(["git", "fetch"]).success();
|
|
|
|
// Untrack all bookmarks
|
|
work_dir.run_jj(["bookmark", "untrack", "*"]).success();
|
|
|
|
// Fetch with --tracked should indicate nothing changed
|
|
let output = work_dir.run_jj(["git", "fetch", "--tracked"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Nothing changed.
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_tracked_multiple_remotes() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");
|
|
test_env.add_config("remotes.upstream.auto-track-bookmarks = '*'");
|
|
|
|
// Set up two remotes with different branches
|
|
let origin_path = test_env.env_root().join("origin");
|
|
let origin_repo = git::init(origin_path.clone());
|
|
add_commit_to_branch(&origin_repo, "main", "origin main commit");
|
|
add_commit_to_branch(&origin_repo, "feature1", "origin feature1 commit");
|
|
add_commit_to_branch(&origin_repo, "feature2", "origin feature2 commit");
|
|
|
|
let upstream_path = test_env.env_root().join("upstream");
|
|
let upstream_repo = git::init(upstream_path.clone());
|
|
add_commit_to_branch(&upstream_repo, "main", "upstream main commit");
|
|
add_commit_to_branch(&upstream_repo, "develop", "upstream develop commit");
|
|
add_commit_to_branch(&upstream_repo, "hotfix", "upstream hotfix commit");
|
|
|
|
// Initialize jj repo
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
// Add both remotes
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../origin"])
|
|
.success();
|
|
work_dir
|
|
.run_jj(["git", "remote", "add", "upstream", "../upstream"])
|
|
.success();
|
|
|
|
// Initial fetch from both remotes to set up tracking
|
|
work_dir.run_jj(["git", "fetch", "--all-remotes"]).success();
|
|
|
|
// Track different branches from different remotes
|
|
work_dir
|
|
.run_jj(["bookmark", "track", "feature1", "--remote=origin"])
|
|
.success();
|
|
work_dir
|
|
.run_jj(["bookmark", "track", "develop", "--remote=upstream"])
|
|
.success();
|
|
|
|
// Untrack some branches to test --tracked behavior
|
|
work_dir
|
|
.run_jj(["bookmark", "untrack", "feature2", "--remote=origin"])
|
|
.success();
|
|
work_dir
|
|
.run_jj(["bookmark", "untrack", "hotfix", "--remote=upstream"])
|
|
.success();
|
|
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
develop: yzkwtzyq 4217fc8a upstream develop commit
|
|
@upstream: yzkwtzyq 4217fc8a upstream develop commit
|
|
feature1: ovvpyryn 8a4b3895 origin feature1 commit
|
|
@origin: ovvpyryn 8a4b3895 origin feature1 commit
|
|
feature2: ysxnuyrn 95a1c2bd origin feature2 commit
|
|
feature2@origin: ysxnuyrn 95a1c2bd origin feature2 commit
|
|
hotfix: pozyxktk e9e38ee9 upstream hotfix commit
|
|
hotfix@upstream: pozyxktk e9e38ee9 upstream hotfix commit
|
|
main (conflicted):
|
|
+ orvppysl 25f66480 origin main commit
|
|
+ nrlvptqt f241ccf9 upstream main commit
|
|
@origin (behind by 1 commits): orvppysl 25f66480 origin main commit
|
|
@upstream (behind by 1 commits): nrlvptqt f241ccf9 upstream main commit
|
|
[EOF]
|
|
");
|
|
|
|
// Add new commits to tracked branches on both remotes
|
|
add_commit_to_branch(&origin_repo, "feature1", "new origin feature1 commit");
|
|
add_commit_to_branch(&upstream_repo, "develop", "new upstream develop commit");
|
|
|
|
// Add new commits to untracked branches
|
|
add_commit_to_branch(&origin_repo, "feature2", "new origin feature2 commit");
|
|
add_commit_to_branch(&upstream_repo, "hotfix", "new upstream hotfix commit");
|
|
|
|
// Fetch only tracked branches from all remotes
|
|
work_dir
|
|
.run_jj(["git", "fetch", "--tracked", "--all-remotes"])
|
|
.success();
|
|
|
|
// Only the tracked branches should be updated (feature1 and develop)
|
|
// Untracked branches (feature2, hotfix) should remain at old commits
|
|
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
|
develop: kmsovkut 8b5845da (empty) new upstream develop commit
|
|
@upstream: kmsovkut 8b5845da (empty) new upstream develop commit
|
|
feature1: rmmunkwl d676351d (empty) new origin feature1 commit
|
|
@origin: rmmunkwl d676351d (empty) new origin feature1 commit
|
|
feature2: ysxnuyrn 95a1c2bd origin feature2 commit
|
|
feature2@origin: ysxnuyrn 95a1c2bd origin feature2 commit
|
|
hotfix: pozyxktk e9e38ee9 upstream hotfix commit
|
|
hotfix@upstream: pozyxktk e9e38ee9 upstream hotfix commit
|
|
main (conflicted):
|
|
+ orvppysl 25f66480 origin main commit
|
|
+ nrlvptqt f241ccf9 upstream main commit
|
|
@origin (behind by 1 commits): orvppysl 25f66480 origin main commit
|
|
@upstream (behind by 1 commits): nrlvptqt f241ccf9 upstream main commit
|
|
[EOF]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_git_fetch_auto_track_bookmarks() {
|
|
let test_env = TestEnvironment::default();
|
|
let root_dir = test_env.work_dir("");
|
|
test_env.add_config(
|
|
"
|
|
[remotes.origin]
|
|
auto-track-bookmarks = 'mine/*'
|
|
",
|
|
);
|
|
|
|
root_dir
|
|
.run_jj(["git", "init", "--colocate", "origin"])
|
|
.success();
|
|
let origin_dir = test_env.work_dir("origin");
|
|
origin_dir.run_jj(["b", "c", "mine/foo"]).success();
|
|
origin_dir.run_jj(["b", "c", "not-mine/foo"]).success();
|
|
origin_dir.run_jj(["commit", "-mfoo"]).success();
|
|
let output = origin_dir.run_jj(["show", "@-"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
Commit ID: d7828da83253475bf10c2ae6bd3f0f84bf4604c1
|
|
Change ID: qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu
|
|
Bookmarks: mine/foo not-mine/foo mine/foo@git not-mine/foo@git
|
|
Author : Test User <test.user@example.com> (2001-02-03 08:05:10)
|
|
Committer: Test User <test.user@example.com> (2001-02-03 08:05:10)
|
|
|
|
foo
|
|
|
|
[EOF]
|
|
");
|
|
|
|
root_dir.run_jj(["git", "init", "repo"]).success();
|
|
let repo_dir = test_env.work_dir("repo");
|
|
repo_dir
|
|
.run_jj(["git", "remote", "add", "origin", "../origin/.git"])
|
|
.success();
|
|
|
|
let output = repo_dir.run_jj(["git", "fetch"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
bookmark: mine/foo@origin [new] tracked
|
|
bookmark: not-mine/foo@origin [new] untracked
|
|
[EOF]
|
|
");
|
|
}
|