just playing with tangled
at diffedit3 135 lines 4.6 kB view raw
1// Copyright 2020 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use jj_lib::object_id::ObjectId; 16use jj_lib::repo::Repo; 17use jj_lib::rewrite::merge_commit_trees; 18use tracing::instrument; 19 20use crate::cli_util::CommandHelper; 21use crate::command_error::{user_error, CommandError}; 22use crate::description_util::{ 23 description_template_for_commit, edit_description, join_message_paragraphs, 24}; 25use crate::ui::Ui; 26 27/// Update the description and create a new change on top. 28#[derive(clap::Args, Clone, Debug)] 29#[command(visible_aliases=&["ci"])] 30pub(crate) struct CommitArgs { 31 /// Interactively choose which changes to include in the first commit 32 #[arg(short, long)] 33 interactive: bool, 34 /// Specify diff editor to be used (implies --interactive) 35 #[arg(long, value_name = "NAME")] 36 tool: Option<String>, 37 /// The change description to use (don't open editor) 38 #[arg(long = "message", short, value_name = "MESSAGE")] 39 message_paragraphs: Vec<String>, 40 /// Put these paths in the first commit 41 #[arg(value_hint = clap::ValueHint::AnyPath)] 42 paths: Vec<String>, 43} 44 45#[instrument(skip_all)] 46pub(crate) fn cmd_commit( 47 ui: &mut Ui, 48 command: &CommandHelper, 49 args: &CommitArgs, 50) -> Result<(), CommandError> { 51 let mut workspace_command = command.workspace_helper(ui)?; 52 53 let commit_id = workspace_command 54 .get_wc_commit_id() 55 .ok_or_else(|| user_error("This command requires a working copy"))?; 56 let commit = workspace_command.repo().store().get_commit(commit_id)?; 57 let matcher = workspace_command 58 .parse_file_patterns(&args.paths)? 59 .to_matcher(); 60 let advanceable_branches = workspace_command.get_advanceable_branches(commit.parent_ids())?; 61 let diff_selector = 62 workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?; 63 let mut tx = workspace_command.start_transaction(); 64 let base_tree = merge_commit_trees(tx.repo(), &commit.parents())?; 65 let instructions = format!( 66 "\ 67You are splitting the working-copy commit: {} 68 69The diff initially shows all changes. Adjust the right side until it shows the 70contents you want for the first commit. The remainder will be included in the 71new working-copy commit. 72", 73 tx.format_commit_summary(&commit) 74 ); 75 let tree_id = diff_selector.select( 76 &base_tree, 77 &commit.tree()?, 78 matcher.as_ref(), 79 Some(&instructions), 80 )?; 81 let middle_tree = tx.repo().store().get_root_tree(&tree_id)?; 82 if !args.paths.is_empty() && middle_tree.id() == base_tree.id() { 83 writeln!( 84 ui.warning_default(), 85 "The given paths do not match any file: {}", 86 args.paths.join(" ") 87 )?; 88 } 89 90 let template = description_template_for_commit( 91 ui, 92 command.settings(), 93 tx.base_workspace_helper(), 94 "", 95 commit.description(), 96 &base_tree, 97 &middle_tree, 98 )?; 99 100 let description = if !args.message_paragraphs.is_empty() { 101 join_message_paragraphs(&args.message_paragraphs) 102 } else { 103 edit_description(tx.base_repo(), &template, command.settings())? 104 }; 105 106 let new_commit = tx 107 .mut_repo() 108 .rewrite_commit(command.settings(), &commit) 109 .set_tree_id(tree_id) 110 .set_description(description) 111 .write()?; 112 let workspace_ids = tx 113 .mut_repo() 114 .view() 115 .workspaces_for_wc_commit_id(commit.id()); 116 if !workspace_ids.is_empty() { 117 let new_wc_commit = tx 118 .mut_repo() 119 .new_commit( 120 command.settings(), 121 vec![new_commit.id().clone()], 122 commit.tree_id().clone(), 123 ) 124 .write()?; 125 126 // Does nothing if there's no branches to advance. 127 tx.advance_branches(advanceable_branches, new_commit.id()); 128 129 for workspace_id in workspace_ids { 130 tx.mut_repo().edit(workspace_id, &new_wc_commit).unwrap(); 131 } 132 } 133 tx.finish(ui, format!("commit {}", commit.id().hex()))?; 134 Ok(()) 135}