just playing with tangled
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at ig/vimdiffwarn 177 lines 6.4 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 std::collections::HashSet; 16use std::io::Write as _; 17 18use clap_complete::ArgValueCandidates; 19use itertools::Itertools as _; 20use jj_lib::backend::CommitId; 21use jj_lib::repo::Repo as _; 22use jj_lib::rewrite::merge_commit_trees; 23use jj_lib::rewrite::rebase_commit; 24use tracing::instrument; 25 26use crate::cli_util::compute_commit_location; 27use crate::cli_util::CommandHelper; 28use crate::cli_util::RevisionArg; 29use crate::command_error::CommandError; 30use crate::complete; 31use crate::description_util::join_message_paragraphs; 32use crate::ui::Ui; 33 34/// Create a new, empty change and (by default) edit it in the working copy 35/// 36/// By default, `jj` will edit the new change, making the [working copy] 37/// represent the new commit. This can be avoided with `--no-edit`. 38/// 39/// Note that you can create a merge commit by specifying multiple revisions as 40/// argument. For example, `jj new @ main` will create a new commit with the 41/// working copy and the `main` bookmark as parents. 42/// 43/// [working copy]: 44/// https://jj-vcs.github.io/jj/latest/working-copy/ 45#[derive(clap::Args, Clone, Debug)] 46pub(crate) struct NewArgs { 47 /// Parent(s) of the new change 48 #[arg( 49 default_value = "@", 50 value_name = "REVSETS", 51 add = ArgValueCandidates::new(complete::all_revisions) 52 )] 53 revisions: Option<Vec<RevisionArg>>, 54 /// Ignored (but lets you pass `-d`/`-r` for consistency with other 55 /// commands) 56 #[arg(short = 'd', hide = true, short_alias = 'r', action = clap::ArgAction::Count)] 57 unused_destination: u8, 58 /// The change description to use 59 #[arg(long = "message", short, value_name = "MESSAGE")] 60 message_paragraphs: Vec<String>, 61 /// Do not edit the newly created change 62 #[arg(long, conflicts_with = "_edit")] 63 no_edit: bool, 64 /// No-op flag to pair with --no-edit 65 #[arg(long, hide = true)] 66 _edit: bool, 67 /// Insert the new change after the given commit(s) 68 #[arg( 69 long, 70 short = 'A', 71 visible_alias = "after", 72 conflicts_with = "revisions", 73 value_name = "REVSETS", 74 add = ArgValueCandidates::new(complete::all_revisions), 75 )] 76 insert_after: Option<Vec<RevisionArg>>, 77 /// Insert the new change before the given commit(s) 78 #[arg( 79 long, 80 short = 'B', 81 visible_alias = "before", 82 conflicts_with = "revisions", 83 value_name = "REVSETS", 84 add = ArgValueCandidates::new(complete::mutable_revisions), 85 )] 86 insert_before: Option<Vec<RevisionArg>>, 87} 88 89#[instrument(skip_all)] 90pub(crate) fn cmd_new( 91 ui: &mut Ui, 92 command: &CommandHelper, 93 args: &NewArgs, 94) -> Result<(), CommandError> { 95 let mut workspace_command = command.workspace_helper(ui)?; 96 97 let (parent_commit_ids, child_commit_ids) = compute_commit_location( 98 ui, 99 &workspace_command, 100 // HACK: `args.revisions` will always have a value due to the `default_value`, however 101 // `compute_commit_location` requires that the `destination` argument is mutually exclusive 102 // to `insert_after` and `insert_before` arguments. 103 if args.insert_before.is_some() || args.insert_after.is_some() { 104 None 105 } else { 106 args.revisions.as_deref() 107 }, 108 args.insert_after.as_deref(), 109 args.insert_before.as_deref(), 110 "new commit", 111 )?; 112 let parent_commits: Vec<_> = parent_commit_ids 113 .iter() 114 .map(|commit_id| workspace_command.repo().store().get_commit(commit_id)) 115 .try_collect()?; 116 let mut advance_bookmarks_target = None; 117 let mut advanceable_bookmarks = vec![]; 118 119 if args.insert_before.is_none() && args.insert_after.is_none() { 120 let should_advance_bookmarks = parent_commits.len() == 1; 121 if should_advance_bookmarks { 122 advance_bookmarks_target = Some(parent_commit_ids[0].clone()); 123 advanceable_bookmarks = 124 workspace_command.get_advanceable_bookmarks(parent_commits[0].parent_ids())?; 125 } 126 }; 127 128 let parent_commit_ids_set: HashSet<CommitId> = parent_commit_ids.iter().cloned().collect(); 129 130 let mut tx = workspace_command.start_transaction(); 131 let merged_tree = merge_commit_trees(tx.repo(), &parent_commits)?; 132 let new_commit = tx 133 .repo_mut() 134 .new_commit(parent_commit_ids, merged_tree.id()) 135 .set_description(join_message_paragraphs(&args.message_paragraphs)) 136 .write()?; 137 138 let child_commits: Vec<_> = child_commit_ids 139 .iter() 140 .map(|commit_id| tx.repo().store().get_commit(commit_id)) 141 .try_collect()?; 142 let mut num_rebased = 0; 143 for child_commit in child_commits { 144 let new_parent_ids = child_commit 145 .parent_ids() 146 .iter() 147 .filter(|id| !parent_commit_ids_set.contains(id)) 148 .cloned() 149 .chain(std::iter::once(new_commit.id().clone())) 150 .collect_vec(); 151 rebase_commit(tx.repo_mut(), child_commit, new_parent_ids)?; 152 num_rebased += 1; 153 } 154 num_rebased += tx.repo_mut().rebase_descendants()?; 155 156 if args.no_edit { 157 if let Some(mut formatter) = ui.status_formatter() { 158 write!(formatter, "Created new commit ")?; 159 tx.write_commit_summary(formatter.as_mut(), &new_commit)?; 160 writeln!(formatter)?; 161 } 162 } else { 163 tx.edit(&new_commit)?; 164 // The description of the new commit will be printed by tx.finish() 165 } 166 if num_rebased > 0 { 167 writeln!(ui.status(), "Rebased {num_rebased} descendant commits")?; 168 } 169 170 // Does nothing if there's no bookmarks to advance. 171 if let Some(target) = advance_bookmarks_target { 172 tx.advance_bookmarks(advanceable_bookmarks, &target); 173 } 174 175 tx.finish(ui, "new empty commit")?; 176 Ok(()) 177}