cli: make jj git push push given branch

Now that we have native branches, we can make `jj git push` only be
about pushing a branch to a remote branch with the same name.

We may want to add back support for the more advanced case of pushing
an arbitrary commit to an arbitrary branch later, but let's get the
common case simplified first.
This commit is contained in:
Martin von Zweigbergk 2021-08-04 14:30:06 -07:00
parent f85613cf66
commit 7dc82c1580
3 changed files with 56 additions and 22 deletions

View file

@ -743,6 +743,10 @@ impl MutableRepo {
self.invalidate_evolution();
}
pub fn get_branch(&mut self, name: &str) -> Option<&BranchTarget> {
self.view.get_branch(name)
}
pub fn set_branch(&mut self, name: String, target: BranchTarget) {
self.view.set_branch(name, target);
}

View file

@ -133,6 +133,10 @@ impl View {
}
}
pub fn get_branch(&self, name: &str) -> Option<&BranchTarget> {
self.data.branches.get(name)
}
pub fn set_branch(&mut self, name: String, target: BranchTarget) {
self.data.branches.insert(name, target);
}

View file

@ -771,25 +771,18 @@ fn get_app<'a, 'b>() -> App<'a, 'b> {
)
.subcommand(
SubCommand::with_name("push")
.about("Push a revision to a git remote branch")
.about("Push a branch to a git remote")
.arg(
Arg::with_name("revision")
.long("revision")
.short("r")
Arg::with_name("branch")
.long("branch")
.takes_value(true)
.default_value(":@"),
.required(true),
)
.arg(
Arg::with_name("remote")
.long("remote")
.takes_value(true)
.default_value("origin"),
)
.arg(
Arg::with_name("branch")
.long("branch")
.takes_value(true)
.required(true),
),
)
.subcommand(
@ -2578,19 +2571,52 @@ fn cmd_git_push(
_git_matches: &ArgMatches,
cmd_matches: &ArgMatches,
) -> Result<(), CommandError> {
let mut repo_command = command.repo_helper(ui)?;
let commit = repo_command.resolve_revision_arg(cmd_matches)?;
if commit.is_open() {
return Err(CommandError::UserError(
"Won't push open commit".to_string(),
));
}
let repo_command = command.repo_helper(ui)?;
let repo = repo_command.repo();
let git_repo = get_git_repo(repo.store())?;
let remote_name = cmd_matches.value_of("remote").unwrap();
let branch_name = cmd_matches.value_of("branch").unwrap();
git::push_commit(&git_repo, &commit, remote_name, branch_name)
.map_err(|err| CommandError::UserError(err.to_string()))?;
let remote_name = cmd_matches.value_of("remote").unwrap();
let maybe_branch_target = repo.view().get_branch(branch_name);
if maybe_branch_target.is_none() {
return Err(CommandError::UserError(format!(
"Branch {} doesn't exist",
branch_name
)));
}
let branch_target = maybe_branch_target.unwrap();
if branch_target.local_target.as_ref() == branch_target.remote_targets.get(remote_name) {
writeln!(
ui,
"Branch {}@{} already matches {}",
branch_name, remote_name, branch_name
)?;
return Ok(());
}
let git_repo = get_git_repo(repo.store())?;
if let Some(new_target) = &branch_target.local_target {
match new_target {
RefTarget::Conflict { .. } => {
return Err(CommandError::UserError(format!(
"Branch {} is conflicted",
branch_name
)));
}
RefTarget::Normal(new_target_id) => {
let new_target_commit = repo.store().get_commit(new_target_id)?;
if new_target_commit.is_open() {
return Err(CommandError::UserError(
"Won't push open commit".to_string(),
));
}
git::push_commit(&git_repo, &new_target_commit, remote_name, branch_name)
.map_err(|err| CommandError::UserError(err.to_string()))?;
}
}
} else {
// TODO: Delete remote branch if the local branch was deleted
}
let mut tx = repo_command.start_transaction("import git refs");
git::import_refs(tx.mut_repo(), &git_repo)
.map_err(|err| CommandError::UserError(err.to_string()))?;