just playing with tangled

Compare changes

Choose any two refs to compare.

+7 -8
CHANGELOG.md
··· 67 67 * Templates can now do arithmetic on integers with the `+`, `-`, `*`, `/`, and `%` 68 68 infix operators. 69 69 70 - * `jj split` assigns the change id and the bookmarks of the source revision 71 - to the revision with the non-selected changes. 72 - You can opt out of this change by setting `split.legacy-bookmark-behavior = true`, 73 - but this will likely be removed in a future release. 74 - 75 70 * Evolution history is now stored in the operation log. `jj evolog` can show 76 71 associated operations for commits created by new jj. 77 72 ··· 83 78 84 79 * `jj parallelize` can now parallelize groups of changes that _start_ with an 85 80 immutable change, but do not contain any other immutable changes. 81 + 82 + * `jj` will no longer warn about deprecated paths on macOS if the configured 83 + XDG directory is the deprecated one (~/Library/Application Support). 86 84 87 85 ### Packaging changes 88 86 ··· 120 118 `template-aliases.default_commit_description`. Please also consider using 121 119 [`templates.draft_commit_description`](docs/config.md#default-description), 122 120 and/or [`templates.commit_trailers`](docs/config.md#commit-trailers). 121 + 122 + * On macOS, config.toml files in `~/Library/Application Support/jj` are 123 + deprecated; one should instead use `$XDG_CONFIG_HOME/jj` 124 + (defaults to `~/.config/jj`) 123 125 124 126 ### New features 125 127 ··· 324 326 325 327 * The 'how to resolve conflicts' hint that is shown when conflicts appear can 326 328 be hidden by setting `hints.resolving-conflicts = false`. 327 - 328 - * `jj squash` now has a `--restore-descendants` option to preserve the snapshots 329 - of the children of the modified commits. 330 329 331 330 * `jj op diff` and `jj op log --op-diff` now show changes to which commits 332 331 correspond to working copies.
+2 -6
cli/build.rs
··· 61 61 "log", 62 62 "--no-graph", 63 63 "-r=@-", 64 - "-T=commit_id ++ '-'", 64 + "-T=commit_id", 65 65 ]) 66 66 .output() 67 67 { 68 68 if output.status.success() { 69 - let mut parent_commits = String::from_utf8(output.stdout).unwrap(); 70 - // TODO(ilyagr): The `test_version` integration test shoult be fixed 71 - // to succeed even if there is more than one parent commit. 72 - parent_commits.truncate(parent_commits.trim_end_matches('-').len()); 73 - return Some(parent_commits); 69 + return Some(String::from_utf8(output.stdout).unwrap()); 74 70 } 75 71 } 76 72
+13 -3
cli/src/cli_util.rs
··· 3858 3858 "Did you update to a commit where the directory doesn't exist?", 3859 3859 ) 3860 3860 })?; 3861 - let mut config_env = ConfigEnv::from_environment(); 3861 + let mut config_env = ConfigEnv::from_environment(ui); 3862 3862 let mut last_config_migration_descriptions = Vec::new(); 3863 3863 let mut migrate_config = |config: &mut StackedConfig| -> Result<(), CommandError> { 3864 3864 last_config_migration_descriptions = ··· 3937 3937 ui.reset(&config)?; 3938 3938 3939 3939 // Print only the last migration messages to omit duplicates. 3940 - for desc in &last_config_migration_descriptions { 3941 - writeln!(ui.warning_default(), "Deprecated config: {desc}")?; 3940 + for (source, desc) in &last_config_migration_descriptions { 3941 + let source_str = match source { 3942 + ConfigSource::Default => "default-provided", 3943 + ConfigSource::EnvBase | ConfigSource::EnvOverrides => "environment-provided", 3944 + ConfigSource::User => "user-level", 3945 + ConfigSource::Repo => "repo-level", 3946 + ConfigSource::CommandArg => "CLI-provided", 3947 + }; 3948 + writeln!( 3949 + ui.warning_default(), 3950 + "Deprecated {source_str} config: {desc}" 3951 + )?; 3942 3952 } 3943 3953 3944 3954 if args.global_args.repository.is_some() {
+1 -6
cli/src/commands/commit.rs
··· 12 12 // See the License for the specific language governing permissions and 13 13 // limitations under the License. 14 14 15 - use clap_complete::ArgValueCandidates; 16 15 use clap_complete::ArgValueCompleter; 17 16 use indoc::writedoc; 18 17 use jj_lib::backend::Signature; ··· 38 37 #[arg(short, long)] 39 38 interactive: bool, 40 39 /// Specify diff editor to be used (implies --interactive) 41 - #[arg( 42 - long, 43 - value_name = "NAME", 44 - add = ArgValueCandidates::new(complete::diff_editors), 45 - )] 40 + #[arg(long, value_name = "NAME")] 46 41 tool: Option<String>, 47 42 /// The change description to use (don't open editor) 48 43 #[arg(long = "message", short, value_name = "MESSAGE")]
+1 -6
cli/src/commands/diffedit.rs
··· 14 14 15 15 use std::io::Write as _; 16 16 17 - use clap_complete::ArgValueCandidates; 18 17 use clap_complete::ArgValueCompleter; 19 18 use itertools::Itertools as _; 20 19 use jj_lib::matchers::EverythingMatcher; ··· 78 77 )] 79 78 to: Option<RevisionArg>, 80 79 /// Specify diff editor to be used 81 - #[arg( 82 - long, 83 - value_name = "NAME", 84 - add = ArgValueCandidates::new(complete::diff_editors), 85 - )] 80 + #[arg(long, value_name = "NAME")] 86 81 tool: Option<String>, 87 82 /// Preserve the content (not the diff) when rebasing descendants 88 83 ///
+9 -60
cli/src/commands/evolog.rs
··· 19 19 use clap_complete::ArgValueCompleter; 20 20 use itertools::Itertools as _; 21 21 use jj_lib::commit::Commit; 22 - use jj_lib::copies::CopyRecords; 23 22 use jj_lib::evolution::walk_predecessors; 24 23 use jj_lib::graph::reverse_graph; 25 24 use jj_lib::graph::GraphEdge; 26 25 use jj_lib::matchers::EverythingMatcher; 27 - use jj_lib::repo::Repo as _; 28 - use jj_lib::rewrite::merge_commit_trees; 29 26 use tracing::instrument; 30 27 31 28 use super::log::get_node_template; ··· 35 32 use crate::cli_util::RevisionArg; 36 33 use crate::command_error::CommandError; 37 34 use crate::complete; 38 - use crate::diff_util::get_copy_records; 39 35 use crate::diff_util::DiffFormatArgs; 40 36 use crate::graphlog::get_graphlog; 41 37 use crate::graphlog::GraphStyle; ··· 89 85 /// contaminated by unrelated changes. 90 86 #[arg(long, short = 'p')] 91 87 patch: bool, 92 - /// Changes the behavior of `--patch`, `--git`, etc to show diffs from 93 - /// rebases 94 - /// 95 - /// Implies `--patch` if no other diff format is requested. 96 - /// 97 - /// Normally, `jj evolog -p` shows a so-called "interdiff", temporarily 98 - /// rebasing the versions of a revision to the same parents, in order to 99 - /// omit differences in the file contents that are caused by rebases. 100 - /// 101 - /// This option disables this behavior, and shows diffs between the contents 102 - /// of the different versions without modification (as snapshots). 103 - /// 104 - /// Sometimes, `--diff-snapshots` can show fewer differences to be shown. 105 - /// For example, let's say the current revision is not empty and we perform 106 - /// `jj squash --keep-empty -r @` to make it empty. Then, `jj evolog -p 107 - /// --diff-snapshots` will not show any changes since the contents of the 108 - /// files in the current revision did not change. However, `jj evolog -p` 109 - /// will show a change, representing the fact that a non-empty revision 110 - /// became empty. 111 - #[arg(long)] 112 - diff_snapshots: bool, 113 88 #[command(flatten)] 114 89 diff_format: DiffFormatArgs, 115 90 } ··· 124 99 125 100 let start_commit = workspace_command.resolve_single_rev(ui, &args.revision)?; 126 101 127 - let diff_renderer = workspace_command 128 - .diff_renderer_for_log(&args.diff_format, args.patch || args.diff_snapshots)?; 102 + let diff_renderer = workspace_command.diff_renderer_for_log(&args.diff_format, args.patch)?; 129 103 let graph_style = GraphStyle::from_settings(workspace_command.settings())?; 130 104 let with_content_format = LogContentFormat::new(ui, workspace_command.settings())?; 131 105 ··· 199 173 if let Some(renderer) = &diff_renderer { 200 174 let predecessors: Vec<_> = entry.predecessors().try_collect()?; 201 175 let mut formatter = ui.new_formatter(&mut buffer); 202 - if args.diff_snapshots { 203 - let mut copy_records = CopyRecords::default(); 204 - for p in &predecessors { 205 - let records = get_copy_records( 206 - workspace_command.repo().store(), 207 - p.id(), 208 - entry.commit.id(), 209 - &EverythingMatcher, 210 - )?; 211 - copy_records.add_records(records)?; 212 - } 213 - let from_tree = 214 - merge_commit_trees(workspace_command.repo().as_ref(), &predecessors)?; 215 - renderer.show_diff( 216 - ui, 217 - formatter.as_mut(), 218 - &from_tree, 219 - &entry.commit.tree()?, 220 - &EverythingMatcher, 221 - &copy_records, 222 - within_graph.width(), 223 - )?; 224 - } else { 225 - renderer.show_inter_diff( 226 - ui, 227 - formatter.as_mut(), 228 - &predecessors, 229 - &entry.commit, 230 - &EverythingMatcher, 231 - within_graph.width(), 232 - )?; 233 - } 176 + renderer.show_inter_diff( 177 + ui, 178 + formatter.as_mut(), 179 + &predecessors, 180 + &entry.commit, 181 + &EverythingMatcher, 182 + within_graph.width(), 183 + )?; 234 184 } 235 185 let node_symbol = format_template(ui, &Some(entry.commit.clone()), &node_template); 236 186 graph.add_node( ··· 262 212 if let Some(renderer) = &diff_renderer { 263 213 let predecessors: Vec<_> = entry.predecessors().try_collect()?; 264 214 let width = ui.term_width(); 265 - // TODO 266 215 renderer.show_inter_diff( 267 216 ui, 268 217 formatter,
+4 -10
cli/src/commands/git/fetch.rs
··· 189 189 branches: &[StringPattern], 190 190 remotes: &[&RemoteName], 191 191 ) -> Result<(), CommandError> { 192 - let mut missing_branches = vec![]; 193 192 for branch in branches { 194 193 let matches = remotes.iter().any(|&remote| { 195 194 let remote = StringPattern::exact(remote); ··· 206 205 .is_some() 207 206 }); 208 207 if !matches { 209 - missing_branches.push(branch); 208 + writeln!( 209 + ui.warning_default(), 210 + "No branch matching `{branch}` found on any specified/configured remote", 211 + )?; 210 212 } 211 - } 212 - 213 - if !missing_branches.is_empty() { 214 - writeln!( 215 - ui.warning_default(), 216 - "No branch matching {} found on any specified/configured remote", 217 - missing_branches.iter().map(|b| format!("`{b}`")).join(", ") 218 - )?; 219 213 } 220 214 221 215 Ok(())
+1 -7
cli/src/commands/resolve.rs
··· 12 12 // See the License for the specific language governing permissions and 13 13 // limitations under the License. 14 14 15 - use clap_complete::ArgValueCandidates; 16 15 use clap_complete::ArgValueCompleter; 17 16 use itertools::Itertools as _; 18 17 use jj_lib::object_id::ObjectId as _; ··· 62 61 /// 63 62 /// The built-in merge tools `:ours` and `:theirs` can be used to choose 64 63 /// side #1 and side #2 of the conflict respectively. 65 - #[arg( 66 - long, 67 - conflicts_with = "list", 68 - value_name = "NAME", 69 - add = ArgValueCandidates::new(complete::merge_tools), 70 - )] 64 + #[arg(long, conflicts_with = "list", value_name = "NAME")] 71 65 tool: Option<String>, 72 66 /// Only resolve conflicts in these paths. You can use the `--list` argument 73 67 /// to find paths to use here.
+1 -6
cli/src/commands/restore.rs
··· 14 14 15 15 use std::io::Write as _; 16 16 17 - use clap_complete::ArgValueCandidates; 18 17 use clap_complete::ArgValueCompleter; 19 18 use indoc::formatdoc; 20 19 use itertools::Itertools as _; ··· 97 96 #[arg(long, short)] 98 97 interactive: bool, 99 98 /// Specify diff editor to be used (implies --interactive) 100 - #[arg( 101 - long, 102 - value_name = "NAME", 103 - add = ArgValueCandidates::new(complete::diff_editors), 104 - )] 99 + #[arg(long, value_name = "NAME")] 105 100 tool: Option<String>, 106 101 /// Preserve the content (not the diff) when rebasing descendants 107 102 #[arg(long)]
+11 -15
cli/src/commands/split.rs
··· 14 14 use std::collections::HashMap; 15 15 use std::io::Write as _; 16 16 17 - use clap_complete::ArgValueCandidates; 18 17 use clap_complete::ArgValueCompleter; 19 18 use jj_lib::backend::CommitId; 20 19 use jj_lib::commit::Commit; ··· 50 49 /// 51 50 /// Starts a [diff editor] on the changes in the revision. Edit the right side 52 51 /// of the diff until it has the content you want in the new revision. Once 53 - /// you close the editor, your edited content will be put in a new revision 54 - /// before the original revision, while the remaining changes will replace the 55 - /// original revision. 52 + /// you close the editor, your edited content will replace the previous 53 + /// revision. The remaining changes will be put in a new revision on top. 56 54 /// 57 55 /// [diff editor]: 58 56 /// https://jj-vcs.github.io/jj/latest/config/#editing-diffs ··· 72 70 #[arg(long, short)] 73 71 interactive: bool, 74 72 /// Specify diff editor to be used (implies --interactive) 75 - #[arg( 76 - long, 77 - value_name = "NAME", 78 - add = ArgValueCandidates::new(complete::diff_editors), 79 - )] 73 + #[arg(long, value_name = "NAME")] 80 74 tool: Option<String>, 81 75 /// The revision to split 82 76 #[arg( ··· 225 219 // Prompt the user to select the changes they want for the first commit. 226 220 let target = select_diff(ui, &tx, &target_commit, &matcher, &diff_selector)?; 227 221 228 - let legacy_bookmark_behavior = 229 - !use_move_flags && tx.settings().get_bool("split.legacy-bookmark-behavior")?; 230 - 231 222 // Create the first commit, which includes the changes selected by the user. 232 223 let first_commit = { 233 224 let mut commit_builder = tx.repo_mut().rewrite_commit(&target.commit).detach(); 234 225 commit_builder.set_tree_id(target.selected_tree.id()); 235 - if !legacy_bookmark_behavior { 226 + if use_move_flags { 236 227 commit_builder 237 228 // Generate a new change id so that the commit being split doesn't 238 229 // become divergent. ··· 279 270 commit_builder 280 271 .set_parents(parents) 281 272 .set_tree_id(new_tree.id()); 282 - if legacy_bookmark_behavior { 273 + if !use_move_flags { 283 274 commit_builder 284 275 // Generate a new change id so that the commit being split doesn't 285 276 // become divergent. ··· 416 407 tx.repo_mut() 417 408 .transform_descendants(vec![target.commit.id().clone()], |mut rewriter| { 418 409 num_rebased += 1; 419 - if parallel { 410 + if parallel && legacy_bookmark_behavior { 411 + // The old_parent is the second commit due to the rewrite above. 420 412 rewriter 421 413 .replace_parent(second_commit.id(), [first_commit.id(), second_commit.id()]); 414 + } else if parallel { 415 + rewriter.replace_parent(first_commit.id(), [first_commit.id(), second_commit.id()]); 416 + } else { 417 + rewriter.replace_parent(first_commit.id(), [second_commit.id()]); 422 418 } 423 419 rewriter.rebase()?.write()?; 424 420 Ok(())
+3 -162
cli/src/commands/squash.rs
··· 12 12 // See the License for the specific language governing permissions and 13 13 // limitations under the License. 14 14 15 - use clap_complete::ArgValueCandidates; 16 15 use clap_complete::ArgValueCompleter; 17 16 use indoc::formatdoc; 18 17 use itertools::Itertools as _; ··· 23 22 use jj_lib::repo::Repo as _; 24 23 use jj_lib::rewrite; 25 24 use jj_lib::rewrite::CommitWithSelection; 26 - use jj_lib::rewrite::SquashOptions; 27 25 use tracing::instrument; 28 26 29 27 use crate::cli_util::CommandHelper; ··· 101 99 #[arg(long, short)] 102 100 interactive: bool, 103 101 /// Specify diff editor to be used (implies --interactive) 104 - #[arg( 105 - long, 106 - value_name = "NAME", 107 - add = ArgValueCandidates::new(complete::diff_editors), 108 - )] 102 + #[arg(long, value_name = "NAME")] 109 103 tool: Option<String>, 110 104 /// Move only changes to these paths (instead of all paths) 111 105 #[arg( ··· 118 112 /// The source revision will not be abandoned 119 113 #[arg(long, short)] 120 114 keep_emptied: bool, 121 - /// Preserve the content (not the diff) when rebasing descendants of the 122 - /// source and target commits 123 - /// 124 - /// Only the snapshots of the `--from` and the `--into` commits will be 125 - /// modified. 126 - /// 127 - /// If you'd like to preserve the content of *only* the target's descendants 128 - /// (or *only* the source's), consider using `jj rebase -r` or `jj 129 - /// duplicate` before squashing. 130 - // 131 - // See "NOTE: Not implementing `--restore-{target,source}-descendants`" in 132 - // squash.rs. 133 - // 134 - // TODO: Once it's implemented, we should recommend `jj rebase -r 135 - // --restore-descendants` instead of `jj duplicate`, since you actually 136 - // would need to `squash` twice with `duplicate`. 137 - #[arg(long)] 138 - restore_descendants: bool, 139 115 } 140 116 141 - // NOTE: Not implementing `--restore-{target,source}-descendants` 142 - // -------------------------------------------------------------- 143 - // 144 - // We have `jj squash --restore-descendants --from X --into Y` preserve the 145 - // snapshots of both the descendants of `X` and those of the descendants of `Y`. 146 - // This behavior makes it simple to understand; it does the same thing to the 147 - // child of any commit `jj squash` rewrites. As @yuja pointed out it could even 148 - // be a global flag that would apply to any command that rewrites commits. 149 - // 150 - // In this note, we explain why we choose not to have a flag for `jj squash` 151 - // that preserves *only* the descendants of the source (call it 152 - // `--restore-source-descendants`) or a similar `--restore-target-descendants` 153 - // flag, even though they might seem easy to implement at a glance. 154 - // 155 - // (The same argument applies to `jj rebase --restore-???-descendants`.) 156 - // 157 - // Firstly, such extra flags seem to only be useful in rare cases. If needed, 158 - // they can be simulated. Instead of `squash --restore-target-descendants`, you 159 - // could do `jj rebase -r X -d all:X-; jj squash --restore-descendants --from X 160 - // --into Y`. Instead of `squash --restore-source-descendants`, you could do `jj 161 - // duplicate -r X; jj squash --restore-descendants --from copy_of_X --into Y; jj 162 - // abandon --restore-descendants X`. (TODO: When `jj rebase -r 163 - // --restore-descendants` is implemented, this will become 2 commands instead of 164 - // 3). 165 - // 166 - // Secondly, the behavior of these flags would get confusing in corner cases, 167 - // when the target is an ancestor or descendant of the source, or for ancestors 168 - // of merge commits. For example, consider this commit graph with merge commit 169 - // `Z` where `A` is *not* empty (thanks to @lilyball for suggesting the merge 170 - // commit example): 171 - // 172 - // ``` 173 - // A -> X - 174 - // \ (Example I) 175 - // B -> Y --->Z 176 - // ``` 177 - // 178 - // The behavior of `jj squash --from A --into B --restore-descendants` is easy 179 - // to understand: the snapshots of `X` and `Y` remain the same, and all of their 180 - // descendants also remain the same by normal rebasing rules. 181 - // 182 - // If we allowed `jj squash --from A --into B --restore-target-descendants`, 183 - // what should it mean? It seems clear that `X`'s snapshot should remain the 184 - // same, and `X`'s will change. However, should `Z`'s snapshot change? If we 185 - // follow the logic that Z had one of its parents change and the other stay the 186 - // same, it seems that yes, it should. This is also what the equivalence with 187 - // `jj rebase -r A -d A-; jj squash --from A --into B --restore-descendants` 188 - // would imply. 189 - // 190 - // (A contrarian mind could argue that `Z`'s snapshot should be preserved since 191 - // `Z` is a descendant of the target `B`. We'll put this thought aside for a 192 - // moment and keep going, to see how things get even more confusing.) 193 - // 194 - // Now, let's pretend we squashed `X` and `Y` into `Z` and ask the same 195 - // question. Our graph is now: 196 - // 197 - // ``` 198 - // A - 199 - // \ (Example II) 200 - // B --->Z 201 - // ``` 202 - // 203 - // By the logic above, the snapshot of `Z` will again change after `jj squash 204 - // --from A --into B --restore-target-descendants`. This is unsatisfying and 205 - // would probably be unexpected, since `Z` is a direct child of the target 206 - // commit `B`, so the user might expect its snapshot to be preserved. 207 - // 208 - // Now, there are a few options: 209 - // 210 - // 1. Allow the confusing but seemingly correct definition of 211 - // `--restore-target-descendants` as above. 212 - // 2. Allow `--restore-target-descendants`, but forbid it in some set of 213 - // situations we deem too confusing. 214 - // 3. Have the effect of `jj squash --from A --into B 215 - // --restore-target-descendants` on `Z`'s snapshot differ between Example I 216 - // and Example II. In other words, the behavior will depend on whether there 217 - // are commits (even if they are empty commits!) between `A` and `Z`, or 218 - // between `B` and `Z`. 219 - // 4. Declare that in both Example I and Example II above, the snapshot of `Z` 220 - // should be preserved. 221 - // 222 - // The first problem with this (and with option 3 above) would be that 223 - // `--restore-target-descendants` would now be equivalent to a rebase 224 - // followed by `squash --restore-descendants` *almost* always, but would 225 - // differ in corner cases. 226 - // 227 - // Perhaps more importantly, this would break the important property of `jj 228 - // squash --restore-target-descendants` that its difference from the 229 - // behavior of normal `jj squash` is local; affects only the direct children 230 - // of the modified commits. All others can normally be rebased by normal 231 - // `jj` rules. 232 - // 233 - // If `jj squash --restore-target-descendants` preserved the snapshot of `Z` 234 - // even if there are 100 commit between it and `A`, this would change its 235 - // diff relative to its parents, possibly without any awareness from the 236 - // user that this happened or that `Z` even existed. 237 - // 5. Do not provide `--restore-target-descendants` ourselves, and recommend 238 - // that the user manually does `jj rebase -r X -d all:X-; jj squash 239 - // --restore-descendants --from X --into Y` if they really need it. 240 - // 241 - // The last option seems easiest. It also has the advantage of requiring fewer 242 - // tests and being the simplest to maintain. 243 - // 244 - // Aside: the merge example is probably the easiest to understand and the most 245 - // problematic, but for `X -> A -> B -> C -> D`, both `jj squash --from C 246 - // --into A --restore-target-descendants` and `jj squash --from A --into C 247 - // --restore-source-descendants` have similar problems. 248 - 249 117 #[instrument(skip_all)] 250 118 pub(crate) fn cmd_squash( 251 119 ui: &mut Ui, ··· 298 166 .check_rewritable(sources.iter().chain(std::iter::once(&destination)).ids())?; 299 167 300 168 let mut tx = workspace_command.start_transaction(); 301 - let tx_description = format!( 302 - "squash commits into {}{}", 303 - destination.id().hex(), 304 - if args.restore_descendants { 305 - " while preserving descendant contents" 306 - } else { 307 - "" 308 - } 309 - ); 169 + let tx_description = format!("squash commits into {}", destination.id().hex()); 310 170 let source_commits = select_diff(&tx, &sources, &destination, &matcher, &diff_selector)?; 311 171 if let Some(squashed) = rewrite::squash_commits( 312 172 tx.repo_mut(), 313 173 &source_commits, 314 174 &destination, 315 - SquashOptions { 316 - keep_emptied: args.keep_emptied, 317 - // See "NOTE: Not implementing `--restore-{target,source}-descendants`" in 318 - // squash.rs. 319 - restore_descendants: args.restore_descendants, 320 - }, 175 + args.keep_emptied, 321 176 )? { 322 177 let mut commit_builder = squashed.commit_builder.detach(); 323 178 let new_description = match description { ··· 365 220 }; 366 221 commit_builder.set_description(new_description); 367 222 commit_builder.write(tx.repo_mut())?; 368 - 369 - if args.restore_descendants { 370 - // If !args.restore_descendants, the corresponding steps are done inside 371 - // tx.finish() 372 - let num_reparented = tx.repo_mut().reparent_descendants()?; 373 - if let Some(mut formatter) = ui.status_formatter() { 374 - writeln!( 375 - formatter, 376 - "Rebased {num_reparented} descendant commits (while preserving their content)", 377 - )?; 378 - } 379 - } 380 223 } else { 381 224 if diff_selector.is_interactive() { 382 225 return Err(user_error("No changes selected")); ··· 398 241 } 399 242 } 400 243 } 401 - // TODO: Show the "Rebase NNN descendant commits message", add " (while 402 - // preserving their content)" in the --restore-descendants mode 403 244 tx.finish(ui, tx_description)?; 404 245 Ok(()) 405 246 }
+1 -49
cli/src/complete.rs
··· 34 34 use crate::config::ConfigArgKind; 35 35 use crate::config::ConfigEnv; 36 36 use crate::config::CONFIG_SCHEMA; 37 - use crate::merge_tools::configured_merge_tools; 38 - use crate::merge_tools::MergeEditor; 39 37 use crate::revset_util::load_revset_aliases; 40 38 use crate::ui::Ui; 41 39 ··· 476 474 .collect()) 477 475 }) 478 476 } 479 - pub fn merge_tools() -> Vec<CompletionCandidate> { 480 - with_jj(|_, settings| { 481 - Ok([":builtin", ":ours", ":theirs"] 482 - .into_iter() 483 - .chain( 484 - configured_merge_tools(settings) 485 - .filter(|name| MergeEditor::dummy_with_name(name, settings).is_ok()), 486 - ) 487 - .map(CompletionCandidate::new) 488 - .collect()) 489 - }) 490 - } 491 - 492 - /// Approximate list of known diff editors 493 - /// 494 - /// Diff tools can be used without configuration. Some merge tools that are 495 - /// configured for 3-way merging may not work for diffing/diff editing, and we 496 - /// can't tell which these are. So, this not reliable, but probably good enough 497 - /// for command-line completion. 498 - pub fn diff_editors() -> Vec<CompletionCandidate> { 499 - let builtin_format_kinds: Vec<String> = crate::diff_util::BuiltinFormatKind::ALL_VARIANTS 500 - .iter() 501 - .map(|kind| format!(":{}", kind.to_arg_name())) 502 - .collect(); 503 - with_jj(|_, settings| { 504 - Ok(std::iter::once(":builtin") 505 - .chain(builtin_format_kinds.iter().map(|s| s.as_str())) 506 - .chain(configured_merge_tools(settings)) 507 - .map(CompletionCandidate::new) 508 - .collect()) 509 - }) 510 - } 511 - 512 - /// Approximate list of known diff tools 513 - /// 514 - /// Diff tools can be used without configuration. Some merge tools that are 515 - /// configured for 3-way merging may not work for diffing/diff editing, and we 516 - /// can't tell which these are. So, this not reliable, but probably good enough 517 - /// for command-line completion. 518 - pub fn diff_tools() -> Vec<CompletionCandidate> { 519 - with_jj(|_, settings| { 520 - Ok(configured_merge_tools(settings) 521 - .map(CompletionCandidate::new) 522 - .collect()) 523 - }) 524 - } 525 477 526 478 fn config_keys_rec( 527 479 prefix: ConfigNamePathBuf, ··· 943 895 .and_then(dunce::canonicalize) 944 896 .map_err(user_error)?; 945 897 // No config migration for completion. Simply ignore deprecated variables. 946 - let mut config_env = ConfigEnv::from_environment(); 898 + let mut config_env = ConfigEnv::from_environment(&ui); 947 899 let maybe_cwd_workspace_loader = DefaultWorkspaceLoaderFactory.create(find_workspace_dir(&cwd)); 948 900 let _ = config_env.reload_user_config(&mut raw_config); 949 901 if let Ok(loader) = &maybe_cwd_workspace_loader {
+1 -1
cli/src/config/misc.toml
··· 54 54 # The behavior when this flag is set to false is experimental and may be changed 55 55 # in the future. 56 56 [split] 57 - legacy-bookmark-behavior = false 57 + legacy-bookmark-behavior = true
+34 -5
cli/src/config.rs
··· 43 43 use crate::command_error::config_error_with_message; 44 44 use crate::command_error::CommandError; 45 45 use crate::text_util; 46 + use crate::ui::Ui; 46 47 47 48 // TODO(#879): Consider generating entire schema dynamically vs. static file. 48 49 pub const CONFIG_SCHEMA: &str = include_str!("config-schema.json"); ··· 192 193 fn as_path(&self) -> &Path { 193 194 &self.path 194 195 } 195 - 196 196 fn exists(&self) -> bool { 197 197 match self.state { 198 198 ConfigPathState::Exists => true, ··· 218 218 #[derive(Clone, Default, Debug)] 219 219 struct UnresolvedConfigEnv { 220 220 config_dir: Option<PathBuf>, 221 + // TODO: remove after jj 0.35 221 222 macos_legacy_config_dir: Option<PathBuf>, 222 223 home_dir: Option<PathBuf>, 223 224 jj_config: Option<String>, 224 225 } 225 226 226 227 impl UnresolvedConfigEnv { 227 - fn resolve(self) -> Vec<ConfigPath> { 228 + fn resolve(self, ui: &Ui) -> Vec<ConfigPath> { 228 229 if let Some(paths) = self.jj_config { 229 230 return split_paths(&paths) 230 231 .filter(|path| !path.as_os_str().is_empty()) ··· 283 284 284 285 if let Some(path) = legacy_platform_config_path { 285 286 if path.exists() { 287 + Self::warn_for_deprecated_path( 288 + ui, 289 + path.as_path(), 290 + "~/Library/Application Support/jj", 291 + "~/.config/jj", 292 + ); 286 293 paths.push(path); 287 294 } 288 295 } 289 296 if let Some(path) = legacy_platform_config_dir { 290 297 if path.exists() { 298 + Self::warn_for_deprecated_path( 299 + ui, 300 + path.as_path(), 301 + "~/Library/Application Support/jj", 302 + "~/.config/jj", 303 + ); 291 304 paths.push(path); 292 305 } 293 306 } 294 307 295 308 paths 296 309 } 310 + 311 + fn warn_for_deprecated_path(ui: &Ui, path: &Path, old: &str, new: &str) { 312 + let _ = indoc::writedoc!( 313 + ui.warning_default(), 314 + r" 315 + Deprecated configuration file `{}`. 316 + Configuration files in `{old}` are deprecated, and support will be removed in a future release. 317 + Instead, move your configuration files to `{new}`. 318 + ", 319 + path.display(), 320 + ); 321 + } 297 322 } 298 323 299 324 #[derive(Clone, Debug)] ··· 307 332 308 333 impl ConfigEnv { 309 334 /// Initializes configuration loader based on environment variables. 310 - pub fn from_environment() -> Self { 335 + pub fn from_environment(ui: &Ui) -> Self { 311 336 let config_dir = etcetera::choose_base_strategy() 312 337 .ok() 313 338 .map(|s| s.config_dir()); ··· 322 347 // Library/Preferences is supposed to be exclusively plists 323 348 s.data_dir() 324 349 }) 350 + .filter(|data_dir| { 351 + // User might've purposefully set their config dir to the deprecated one 352 + Some(data_dir) != config_dir.as_ref() 353 + }) 325 354 } else { 326 355 None 327 356 }; ··· 341 370 ConfigEnv { 342 371 home_dir, 343 372 repo_path: None, 344 - user_config_paths: env.resolve(), 373 + user_config_paths: env.resolve(ui), 345 374 repo_config_path: None, 346 375 command: None, 347 376 } ··· 1728 1757 ConfigEnv { 1729 1758 home_dir, 1730 1759 repo_path: None, 1731 - user_config_paths: env.resolve(), 1760 + user_config_paths: env.resolve(&Ui::null()), 1732 1761 repo_config_path: None, 1733 1762 command: None, 1734 1763 }
+3 -19
cli/src/diff_util.rs
··· 23 23 24 24 use bstr::BStr; 25 25 use bstr::BString; 26 - use clap_complete::ArgValueCandidates; 27 26 use futures::executor::block_on_stream; 28 27 use futures::stream::BoxStream; 29 28 use futures::StreamExt as _; ··· 125 124 /// 126 125 /// A builtin format can also be specified as `:<name>`. For example, 127 126 /// `--tool=:git` is equivalent to `--git`. 128 - #[arg( 129 - long, 130 - add = ArgValueCandidates::new(crate::complete::diff_tools), 131 - )] 127 + #[arg(long)] 132 128 pub tool: Option<String>, 133 129 /// Number of lines of context to show 134 130 #[arg(long)] ··· 156 152 } 157 153 158 154 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 159 - pub enum BuiltinFormatKind { 155 + enum BuiltinFormatKind { 160 156 Summary, 161 157 Stat, 162 158 Types, ··· 166 162 } 167 163 168 164 impl BuiltinFormatKind { 169 - // Alternatively, we could use or vendor one of the crates `strum`, 170 - // `enum-iterator`, or `variant_count` (for a check that the length of the array 171 - // is correct). The latter is very simple and is also a nightly feature. 172 - pub const ALL_VARIANTS: &[BuiltinFormatKind] = &[ 173 - Self::Summary, 174 - Self::Stat, 175 - Self::Types, 176 - Self::NameOnly, 177 - Self::Git, 178 - Self::ColorWords, 179 - ]; 180 - 181 165 fn from_name(name: &str) -> Result<Self, String> { 182 166 match name { 183 167 "summary" => Ok(Self::Summary), ··· 221 205 } 222 206 } 223 207 224 - pub fn to_arg_name(self) -> &'static str { 208 + fn to_arg_name(self) -> &'static str { 225 209 match self { 226 210 Self::Summary => "summary", 227 211 Self::Stat => "stat",
+6 -22
cli/src/merge_tools/mod.rs
··· 207 207 } 208 208 } 209 209 210 - /// List configured merge tools (diff editors, diff tools, merge editors) 211 - pub fn configured_merge_tools(settings: &UserSettings) -> impl Iterator<Item = &str> { 212 - settings.table_keys("merge-tools") 213 - } 214 - 215 210 /// Loads external diff/merge tool options from `[merge-tools.<name>]`. 216 211 pub fn get_external_tool_config( 217 212 settings: &UserSettings, ··· 383 378 let tool = MergeTool::get_tool_config(settings, name)? 384 379 .unwrap_or_else(|| MergeTool::external(ExternalMergeTool::with_program(name))); 385 380 Self::new_inner(name, tool, path_converter, conflict_marker_style) 386 - } 387 - 388 - /// For the purposes of testing or checking basic config 389 - pub fn dummy_with_name( 390 - name: &str, 391 - settings: &UserSettings, 392 - ) -> Result<Self, MergeToolConfigError> { 393 - Self::with_name( 394 - name, 395 - settings, 396 - RepoPathUiConverter::Fs { 397 - cwd: "".into(), 398 - base: "".into(), 399 - }, 400 - ConflictMarkerStyle::Diff, 401 - ) 402 381 } 403 382 404 383 /// Loads the default 3-way merge editor from the settings. ··· 786 765 let get = |name, config_text| { 787 766 let config = config_from_string(config_text); 788 767 let settings = UserSettings::from_config(config).unwrap(); 789 - MergeEditor::dummy_with_name(name, &settings).map(|editor| editor.tool) 768 + let path_converter = RepoPathUiConverter::Fs { 769 + cwd: "".into(), 770 + base: "".into(), 771 + }; 772 + MergeEditor::with_name(name, &settings, path_converter, ConflictMarkerStyle::Diff) 773 + .map(|editor| editor.tool) 790 774 }; 791 775 792 776 insta::assert_debug_snapshot!(get(":builtin", "").unwrap(), @"Builtin");
+1 -15
cli/tests/cli-reference@.md.snap
··· 906 906 * `-p`, `--patch` โ€” Show patch compared to the previous version of this change 907 907 908 908 If the previous version has different parents, it will be temporarily rebased to the parents of the new version, so the diff is not contaminated by unrelated changes. 909 - * `--diff-snapshots` โ€” Changes the behavior of `--patch`, `--git`, etc to show diffs from rebases 910 - 911 - Implies `--patch` if no other diff format is requested. 912 - 913 - Normally, `jj evolog -p` shows a so-called "interdiff", temporarily rebasing the versions of a revision to the same parents, in order to omit differences in the file contents that are caused by rebases. 914 - 915 - This option disables this behavior, and shows diffs between the contents of the different versions without modification (as snapshots). 916 - 917 - Sometimes, `--diff-snapshots` can show fewer differences to be shown. For example, let's say the current revision is not empty and we perform `jj squash --keep-empty -r @` to make it empty. Then, `jj evolog -p --diff-snapshots` will not show any changes since the contents of the files in the current revision did not change. However, `jj evolog -p` will show a change, representing the fact that a non-empty revision became empty. 918 909 * `-s`, `--summary` โ€” For each path, show only whether it was modified, added, or deleted 919 910 * `--stat` โ€” Show a histogram of the changes 920 911 * `--types` โ€” For each path, show only its type before and after ··· 2470 2461 2471 2462 Split a revision in two 2472 2463 2473 - Starts a [diff editor] on the changes in the revision. Edit the right side of the diff until it has the content you want in the new revision. Once you close the editor, your edited content will be put in a new revision before the original revision, while the remaining changes will replace the original revision. 2464 + Starts a [diff editor] on the changes in the revision. Edit the right side of the diff until it has the content you want in the new revision. Once you close the editor, your edited content will replace the previous revision. The remaining changes will be put in a new revision on top. 2474 2465 2475 2466 [diff editor]: https://jj-vcs.github.io/jj/latest/config/#editing-diffs 2476 2467 ··· 2533 2524 * `-i`, `--interactive` โ€” Interactively choose which parts to squash 2534 2525 * `--tool <NAME>` โ€” Specify diff editor to be used (implies --interactive) 2535 2526 * `-k`, `--keep-emptied` โ€” The source revision will not be abandoned 2536 - * `--restore-descendants` โ€” Preserve the content (not the diff) when rebasing descendants of the source and target commits 2537 - 2538 - Only the snapshots of the `--from` and the `--into` commits will be modified. 2539 - 2540 - If you'd like to preserve the content of *only* the target's descendants (or *only* the source's), consider using `jj rebase -r` or `jj duplicate` before squashing. 2541 2527 2542 2528 2543 2529
+1 -1
cli/tests/test_commit_command.rs
··· 298 298 โ—† 000000000000 299 299 [EOF] 300 300 ------- stderr ------- 301 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 301 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 302 302 [EOF] 303 303 "#); 304 304 insta::assert_snapshot!(
-61
cli/tests/test_completion.rs
··· 1089 1089 "); 1090 1090 } 1091 1091 1092 - #[test] 1093 - fn test_merge_tools() { 1094 - let mut test_env = TestEnvironment::default(); 1095 - test_env.add_env_var("COMPLETE", "fish"); 1096 - let dir = test_env.env_root(); 1097 - 1098 - let output = test_env.run_jj_in(dir, ["--", "jj", "diff", "--tool", ""]); 1099 - insta::assert_snapshot!(output, @r" 1100 - diffedit3 1101 - diffedit3-ssh 1102 - difft 1103 - kdiff3 1104 - meld 1105 - meld-3 1106 - mergiraf 1107 - smerge 1108 - vimdiff 1109 - vscode 1110 - vscodium 1111 - [EOF] 1112 - "); 1113 - // Includes :builtin 1114 - let output = test_env.run_jj_in(dir, ["--", "jj", "diffedit", "--tool", ""]); 1115 - insta::assert_snapshot!(output, @r" 1116 - :builtin 1117 - :summary 1118 - :stat 1119 - :types 1120 - :name-only 1121 - :git 1122 - :color-words 1123 - diffedit3 1124 - diffedit3-ssh 1125 - difft 1126 - kdiff3 1127 - meld 1128 - meld-3 1129 - mergiraf 1130 - smerge 1131 - vimdiff 1132 - vscode 1133 - vscodium 1134 - [EOF] 1135 - "); 1136 - // Only includes configured merge editors 1137 - let output = test_env.run_jj_in(dir, ["--", "jj", "resolve", "--tool", ""]); 1138 - insta::assert_snapshot!(output, @r" 1139 - :builtin 1140 - :ours 1141 - :theirs 1142 - kdiff3 1143 - meld 1144 - mergiraf 1145 - smerge 1146 - vimdiff 1147 - vscode 1148 - vscodium 1149 - [EOF] 1150 - "); 1151 - } 1152 - 1153 1092 fn create_commit( 1154 1093 work_dir: &TestWorkDir, 1155 1094 name: &str,
+20
cli/tests/test_config_command.rs
··· 971 971 insta::assert_snapshot!(output, @r" 972 972 Make sure I can pick this up 973 973 [EOF] 974 + ------- stderr ------- 975 + Warning: Deprecated configuration file `$TEST_ENV/home/Library/Application Support/jj/config.toml`. 976 + Configuration files in `~/Library/Application Support/jj` are deprecated, and support will be removed in a future release. 977 + Instead, move your configuration files to `~/.config/jj`. 978 + [EOF] 979 + "); 980 + 981 + // if XDG_CONFIG_HOME is ~/Library/Application Support, 982 + // you shouldn't get a warning 983 + let output = test_env.run_jj_with(|cmd| { 984 + cmd.env_remove("JJ_CONFIG") 985 + .env( 986 + "XDG_CONFIG_HOME", 987 + test_env.home_dir().join("Library/Application Support"), 988 + ) 989 + .args(["config", "get", "foo.bar"]) 990 + }); 991 + insta::assert_snapshot!(output, @r" 992 + Make sure I can pick this up 993 + [EOF] 974 994 "); 975 995 976 996 // if you set JJ_CONFIG, you shouldn't get a warning
+2 -2
cli/tests/test_describe_command.rs
··· 618 618 let output = work_dir.run_jj(["describe"]); 619 619 insta::assert_snapshot!(output, @r#" 620 620 ------- stderr ------- 621 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 621 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 622 622 Working copy (@) now at: qpvuntsm 7276dfff TESTED=TODO 623 623 Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) 624 624 [EOF] ··· 639 639 let output = work_dir.run_jj(["describe", "--no-edit", "--reset-author"]); 640 640 insta::assert_snapshot!(output, @r#" 641 641 ------- stderr ------- 642 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 642 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 643 643 Working copy (@) now at: kkmpptxz 7118bcb8 (empty) (no description set) 644 644 Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) 645 645 [EOF]
+3 -3
cli/tests/test_diff_command.rs
··· 253 253 -4 254 254 [EOF] 255 255 ------- stderr ------- 256 - Warning: Deprecated config: ui.diff.format is updated to ui.diff-formatter = ":git" 256 + Warning: Deprecated CLI-provided config: ui.diff.format is updated to ui.diff-formatter = ":git" 257 257 [EOF] 258 258 "#); 259 259 ··· 3138 3138 file3 3139 3139 [EOF] 3140 3140 ------- stderr ------- 3141 - Warning: Deprecated config: ui.diff.tool is renamed to ui.diff-formatter 3142 - Warning: Deprecated config: ui.diff.format is deleted (superseded by ui.diff-formatter) 3141 + Warning: Deprecated CLI-provided config: ui.diff.tool is renamed to ui.diff-formatter 3142 + Warning: Deprecated CLI-provided config: ui.diff.format is deleted (superseded by ui.diff-formatter) 3143 3143 [EOF] 3144 3144 "); 3145 3145
-46
cli/tests/test_evolog_command.rs
··· 171 171 -- operation e0f8e58b3800 (2001-02-03 08:05:08) new empty commit 172 172 [EOF] 173 173 "); 174 - 175 - // With `--diff-snapshots`, the rebase does show a diff 176 - // TODO: Bug, not implemented yet with --no-graph 177 - let output = work_dir.run_jj(["evolog", "--no-graph", "--git", "--diff-snapshots"]); 178 - insta::assert_snapshot!(output, @r" 179 - rlvkpnrz test.user@example.com 2001-02-03 08:05:10 33c10ace 180 - my description 181 - -- operation 3499115d3831 (2001-02-03 08:05:10) snapshot working copy 182 - diff --git a/file1 b/file1 183 - index 0000000000..2ab19ae607 100644 184 - --- a/file1 185 - +++ b/file1 186 - @@ -1,7 +1,1 @@ 187 - -<<<<<<< Conflict 1 of 1 188 - -%%%%%%% Changes from base to side #1 189 - --foo 190 - -+++++++ Contents of side #2 191 - -foo 192 - -bar 193 - ->>>>>>> Conflict 1 of 1 ends 194 - +resolved 195 - rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:09 7f56b2a0 conflict 196 - my description 197 - -- operation eb87ec366530 (2001-02-03 08:05:09) rebase commit 51e08f95160c897080d035d330aead3ee6ed5588 198 - rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:09 51e08f95 199 - my description 200 - -- operation 18a971ce330a (2001-02-03 08:05:09) snapshot working copy 201 - diff --git a/file1 b/file1 202 - index 257cc5642c..3bd1f0e297 100644 203 - --- a/file1 204 - +++ b/file1 205 - @@ -1,1 +1,2 @@ 206 - foo 207 - +bar 208 - diff --git a/file2 b/file2 209 - new file mode 100644 210 - index 0000000000..257cc5642c 211 - --- /dev/null 212 - +++ b/file2 213 - @@ -0,0 +1,1 @@ 214 - +foo 215 - rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:08 b955b72e 216 - (empty) my description 217 - -- operation e0f8e58b3800 (2001-02-03 08:05:08) new empty commit 218 - [EOF] 219 - "); 220 174 } 221 175 222 176 #[test]
+2 -1
cli/tests/test_git_fetch.rs
··· 1038 1038 ]); 1039 1039 insta::assert_snapshot!(output, @r" 1040 1040 ------- stderr ------- 1041 - Warning: No branch matching `noexist1`, `noexist2` found on any specified/configured remote 1041 + Warning: No branch matching `noexist1` found on any specified/configured remote 1042 + Warning: No branch matching `noexist2` found on any specified/configured remote 1042 1043 Nothing changed. 1043 1044 [EOF] 1044 1045 ");
+140 -140
cli/tests/test_split_command.rs
··· 73 73 let output = work_dir.run_jj(["split", "file2"]); 74 74 insta::assert_snapshot!(output, @r" 75 75 ------- stderr ------- 76 - Selected changes : zsuskuln 8a73f71d (no description set) 77 - Remaining changes: qpvuntsm c4d8ebac (no description set) 78 - Working copy (@) now at: qpvuntsm c4d8ebac (no description set) 79 - Parent commit (@-) : zsuskuln 8a73f71d (no description set) 76 + Selected changes : qpvuntsm 6dbc7747 (no description set) 77 + Remaining changes: zsuskuln 42cbbc02 (no description set) 78 + Working copy (@) now at: zsuskuln 42cbbc02 (no description set) 79 + Parent commit (@-) : qpvuntsm 6dbc7747 (no description set) 80 80 [EOF] 81 81 "); 82 82 insta::assert_snapshot!( ··· 92 92 assert!(!test_env.env_root().join("editor1").exists()); 93 93 94 94 insta::assert_snapshot!(get_log_output(&work_dir), @r" 95 - @ qpvuntsmwlqt false 96 - โ—‹ zsuskulnrvyr false 95 + @ zsuskulnrvyr false 96 + โ—‹ qpvuntsmwlqt false 97 97 โ—† zzzzzzzzzzzz true 98 98 [EOF] 99 99 "); ··· 128 128 ------- stderr ------- 129 129 Warning: All changes have been selected, so the original revision will become empty 130 130 Rebased 1 descendant commits 131 - Selected changes : znkkpsqq d6e65134 (no description set) 132 - Remaining changes: zsuskuln aa27eaa3 (empty) (no description set) 133 - Working copy (@) now at: qpvuntsm e94cab21 (no description set) 134 - Parent commit (@-) : zsuskuln aa27eaa3 (empty) (no description set) 131 + Selected changes : qpvuntsm 9fd1c9e1 (no description set) 132 + Remaining changes: znkkpsqq 41e0da21 (empty) (no description set) 133 + Working copy (@) now at: zsuskuln a06e40b8 (no description set) 134 + Parent commit (@-) : znkkpsqq 41e0da21 (empty) (no description set) 135 135 [EOF] 136 136 "); 137 137 138 138 insta::assert_snapshot!(get_log_output(&work_dir), @r" 139 - @ qpvuntsmwlqt false 140 - โ—‹ zsuskulnrvyr true 141 - โ—‹ znkkpsqqskkl false 139 + @ zsuskulnrvyr false 140 + โ—‹ znkkpsqqskkl true 141 + โ—‹ qpvuntsmwlqt false 142 142 โ—† zzzzzzzzzzzz true 143 143 [EOF] 144 144 "); ··· 159 159 ------- stderr ------- 160 160 Warning: No changes have been selected, so the new revision will be empty 161 161 Rebased 1 descendant commits 162 - Selected changes : lylxulpl 3d639d71 (empty) (no description set) 163 - Remaining changes: znkkpsqq 706a0e77 (no description set) 164 - Working copy (@) now at: qpvuntsm 502cf440 (no description set) 165 - Parent commit (@-) : znkkpsqq 706a0e77 (no description set) 162 + Selected changes : qpvuntsm 49416632 (empty) (no description set) 163 + Remaining changes: lylxulpl 718afbf5 (no description set) 164 + Working copy (@) now at: zsuskuln 0ed53ee6 (no description set) 165 + Parent commit (@-) : lylxulpl 718afbf5 (no description set) 166 166 [EOF] 167 167 "); 168 168 169 169 insta::assert_snapshot!(get_log_output(&work_dir), @r" 170 - @ qpvuntsmwlqt false 171 - โ—‹ znkkpsqqskkl false 172 - โ—‹ lylxulplsnyw true 170 + @ zsuskulnrvyr false 171 + โ—‹ lylxulplsnyw false 172 + โ—‹ qpvuntsmwlqt true 173 173 โ—† zzzzzzzzzzzz true 174 174 [EOF] 175 175 "); ··· 207 207 let output = work_dir.run_jj(["split", "file1"]); 208 208 insta::assert_snapshot!(output, @r#" 209 209 ------- stderr ------- 210 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 211 - Selected changes : kkmpptxz 530f78ed part 1 212 - Remaining changes: qpvuntsm 88189e08 part 2 213 - Working copy (@) now at: qpvuntsm 88189e08 part 2 214 - Parent commit (@-) : kkmpptxz 530f78ed part 1 210 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 211 + Selected changes : qpvuntsm c7f7b14b part 1 212 + Remaining changes: kkmpptxz ac33a5a9 part 2 213 + Working copy (@) now at: kkmpptxz ac33a5a9 part 2 214 + Parent commit (@-) : qpvuntsm c7f7b14b part 1 215 215 [EOF] 216 216 "#); 217 217 ··· 236 236 JJ: Lines starting with "JJ:" (like this one) will be removed. 237 237 "#); 238 238 insta::assert_snapshot!(get_log_output(&work_dir), @r#" 239 - @ qpvuntsmwlqt false part 2 240 - โ—‹ kkmpptxzrspx false part 1 239 + @ kkmpptxzrspx false part 2 240 + โ—‹ qpvuntsmwlqt false part 1 241 241 โ—† zzzzzzzzzzzz true 242 242 [EOF] 243 243 ------- stderr ------- 244 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 244 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 245 245 [EOF] 246 246 "#); 247 247 } ··· 265 265 let output = work_dir.run_jj(["split", "file1"]); 266 266 insta::assert_snapshot!(output, @r#" 267 267 ------- stderr ------- 268 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 269 - Selected changes : rlvkpnrz 16dc7e13 TESTED=TODO 270 - Remaining changes: qpvuntsm f40d53f2 (no description set) 271 - Working copy (@) now at: qpvuntsm f40d53f2 (no description set) 272 - Parent commit (@-) : rlvkpnrz 16dc7e13 TESTED=TODO 268 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 269 + Selected changes : qpvuntsm ff633dcc TESTED=TODO 270 + Remaining changes: rlvkpnrz b1d20b7e (no description set) 271 + Working copy (@) now at: rlvkpnrz b1d20b7e (no description set) 272 + Parent commit (@-) : qpvuntsm ff633dcc TESTED=TODO 273 273 [EOF] 274 274 "#); 275 275 ··· 291 291 "#); 292 292 assert!(!test_env.env_root().join("editor2").exists()); 293 293 insta::assert_snapshot!(get_log_output(&work_dir), @r#" 294 - @ qpvuntsmwlqt false 295 - โ—‹ rlvkpnrzqnoo false TESTED=TODO 294 + @ rlvkpnrzqnoo false 295 + โ—‹ qpvuntsmwlqt false TESTED=TODO 296 296 โ—† zzzzzzzzzzzz true 297 297 [EOF] 298 298 ------- stderr ------- 299 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 299 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 300 300 [EOF] 301 301 "#); 302 302 } ··· 346 346 insta::assert_snapshot!(output, @r" 347 347 ------- stderr ------- 348 348 Rebased 2 descendant commits 349 - Selected changes : royxmykx e13e94b9 Add file1 350 - Remaining changes: qpvuntsm cf8ebbab Add file2 351 - Working copy (@) now at: kkmpptxz 73a16519 Add file4 352 - Parent commit (@-) : rlvkpnrz ec4d3a14 Add file3 349 + Selected changes : qpvuntsm 74306e35 Add file1 350 + Remaining changes: royxmykx 0a37745e Add file2 351 + Working copy (@) now at: kkmpptxz 7ee84812 Add file4 352 + Parent commit (@-) : rlvkpnrz d335bd94 Add file3 353 353 [EOF] 354 354 "); 355 - insta::assert_snapshot!(get_log_output(&work_dir), @r" 355 + insta::assert_snapshot!(get_log_output(&work_dir), @r###" 356 356 @ kkmpptxzrspx false Add file4 357 357 โ—‹ rlvkpnrzqnoo false Add file3 358 - โ—‹ qpvuntsmwlqt false Add file2 359 - โ—‹ royxmykxtrkr false Add file1 358 + โ—‹ royxmykxtrkr false Add file2 359 + โ—‹ qpvuntsmwlqt false Add file1 360 360 โ—† zzzzzzzzzzzz true 361 361 [EOF] 362 - "); 362 + "###); 363 363 364 364 // The commit we're splitting has a description, so the user will be 365 365 // prompted to enter a description for each of the commits. ··· 388 388 // - The initial empty commit. 389 389 // - The rewritten commit from the snapshot after the files were added. 390 390 // - The rewritten commit once the description is added during `jj commit`. 391 - // - The rewritten commit after the split with a new change ID. 392 - let evolog_1 = work_dir.run_jj(["evolog", "-r", "royxm"]); 391 + // - The rewritten commit after the split. 392 + let evolog_1 = work_dir.run_jj(["evolog", "-r", "qpvun"]); 393 393 insta::assert_snapshot!(evolog_1, @r" 394 - โ—‹ royxmykx test.user@example.com 2001-02-03 08:05:12 e13e94b9 394 + โ—‹ qpvuntsm test.user@example.com 2001-02-03 08:05:12 74306e35 395 395 โ”‚ Add file1 396 - โ”‚ -- operation a8006fdd66fd (2001-02-03 08:05:12) split commit 1d2499e72cefc8a2b87ebb47569140857b96189f 396 + โ”‚ -- operation 994b490f285d (2001-02-03 08:05:12) split commit 1d2499e72cefc8a2b87ebb47569140857b96189f 397 397 โ—‹ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 1d2499e7 398 398 โ”‚ Add file1 & file2 399 399 โ”‚ -- operation adf4f33386c9 (2001-02-03 08:05:08) commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 ··· 407 407 "); 408 408 409 409 // The evolog for the second commit is the same, except that the change id 410 - // doesn't change after the split. 411 - let evolog_2 = work_dir.run_jj(["evolog", "-r", "qpvun"]); 410 + // changes after the split. 411 + let evolog_2 = work_dir.run_jj(["evolog", "-r", "royxm"]); 412 412 insta::assert_snapshot!(evolog_2, @r" 413 - โ—‹ qpvuntsm test.user@example.com 2001-02-03 08:05:12 cf8ebbab 413 + โ—‹ royxmykx test.user@example.com 2001-02-03 08:05:12 0a37745e 414 414 โ”‚ Add file2 415 - โ”‚ -- operation a8006fdd66fd (2001-02-03 08:05:12) split commit 1d2499e72cefc8a2b87ebb47569140857b96189f 415 + โ”‚ -- operation 994b490f285d (2001-02-03 08:05:12) split commit 1d2499e72cefc8a2b87ebb47569140857b96189f 416 416 โ—‹ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 1d2499e7 417 417 โ”‚ Add file1 & file2 418 418 โ”‚ -- operation adf4f33386c9 (2001-02-03 08:05:08) commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 ··· 461 461 insta::assert_snapshot!(output, @r" 462 462 ------- stderr ------- 463 463 Rebased 1 descendant commits 464 - Selected changes : royxmykx ad21dad2 Add file1 465 - Remaining changes: kkmpptxz 0922bd25 Add file2 466 - Working copy (@) now at: zsuskuln f59cd990 (empty) 2 464 + Selected changes : kkmpptxz cc199567 Add file1 465 + Remaining changes: royxmykx e488409f Add file2 466 + Working copy (@) now at: zsuskuln ace61421 (empty) 2 467 467 Parent commit (@-) : qpvuntsm 884fe9b9 (empty) 1 468 - Parent commit (@-) : kkmpptxz 0922bd25 Add file2 468 + Parent commit (@-) : royxmykx e488409f Add file2 469 469 [EOF] 470 470 "); 471 471 insta::assert_snapshot!(get_log_output(&work_dir), @r" 472 472 @ zsuskulnrvyr true 2 473 473 โ”œโ”€โ•ฎ 474 - โ”‚ โ—‹ kkmpptxzrspx false Add file2 475 - โ”‚ โ—‹ royxmykxtrkr false Add file1 474 + โ”‚ โ—‹ royxmykxtrkr false Add file2 475 + โ”‚ โ—‹ kkmpptxzrspx false Add file1 476 476 โ—‹ โ”‚ qpvuntsmwlqt true 1 477 477 โ”œโ”€โ•ฏ 478 478 โ—† zzzzzzzzzzzz true ··· 498 498 โ—† zzzzzzzzzzzz true 499 499 [EOF] 500 500 ------- stderr ------- 501 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 501 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 502 502 [EOF] 503 503 "#); 504 504 ··· 510 510 let output = work_dir.run_jj(["split", "--parallel", "file1"]); 511 511 insta::assert_snapshot!(output, @r#" 512 512 ------- stderr ------- 513 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 514 - Selected changes : kkmpptxz bd9b3db1 TESTED=TODO 515 - Remaining changes: qpvuntsm 5597b805 (no description set) 516 - Working copy (@) now at: qpvuntsm 5597b805 (no description set) 513 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 514 + Selected changes : qpvuntsm 7bcd474c TESTED=TODO 515 + Remaining changes: kkmpptxz 431886f6 (no description set) 516 + Working copy (@) now at: kkmpptxz 431886f6 (no description set) 517 517 Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) 518 518 Added 0 files, modified 0 files, removed 1 files 519 519 [EOF] 520 520 "#); 521 521 insta::assert_snapshot!(get_log_output(&work_dir), @r#" 522 - @ qpvuntsmwlqt false 523 - โ”‚ โ—‹ kkmpptxzrspx false TESTED=TODO 522 + @ kkmpptxzrspx false 523 + โ”‚ โ—‹ qpvuntsmwlqt false TESTED=TODO 524 524 โ”œโ”€โ•ฏ 525 525 โ—† zzzzzzzzzzzz true 526 526 [EOF] 527 527 ------- stderr ------- 528 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 528 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 529 529 [EOF] 530 530 "#); 531 531 ··· 550 550 // Check the evolog for the first commit. It shows three entries: 551 551 // - The initial empty commit. 552 552 // - The rewritten commit from the snapshot after the files were added. 553 - // - The rewritten commit after the split with a new change ID. 554 - let evolog_1 = work_dir.run_jj(["evolog", "-r", "kkmpp"]); 553 + // - The rewritten commit after the split. 554 + let evolog_1 = work_dir.run_jj(["evolog", "-r", "qpvun"]); 555 555 insta::assert_snapshot!(evolog_1, @r#" 556 - โ—‹ kkmpptxz test.user@example.com 2001-02-03 08:05:09 bd9b3db1 556 + โ—‹ qpvuntsm test.user@example.com 2001-02-03 08:05:09 7bcd474c 557 557 โ”‚ TESTED=TODO 558 - โ”‚ -- operation 372a3799b434 (2001-02-03 08:05:09) split commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 558 + โ”‚ -- operation 2b21c33e1596 (2001-02-03 08:05:09) split commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 559 559 โ—‹ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 f5700f8e 560 560 โ”‚ (no description set) 561 561 โ”‚ -- operation 1663cd1cc445 (2001-02-03 08:05:08) snapshot working copy ··· 564 564 -- operation 8f47435a3990 (2001-02-03 08:05:07) add workspace 'default' 565 565 [EOF] 566 566 ------- stderr ------- 567 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 567 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 568 568 [EOF] 569 569 "#); 570 570 571 571 // The evolog for the second commit is the same, except that the change id 572 - // doesn't change after the split. 573 - let evolog_2 = work_dir.run_jj(["evolog", "-r", "qpvun"]); 572 + // changes after the split. 573 + let evolog_2 = work_dir.run_jj(["evolog", "-r", "kkmpp"]); 574 574 insta::assert_snapshot!(evolog_2, @r#" 575 - @ qpvuntsm test.user@example.com 2001-02-03 08:05:09 5597b805 575 + @ kkmpptxz test.user@example.com 2001-02-03 08:05:09 431886f6 576 576 โ”‚ (no description set) 577 - โ”‚ -- operation 372a3799b434 (2001-02-03 08:05:09) split commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 577 + โ”‚ -- operation 2b21c33e1596 (2001-02-03 08:05:09) split commit f5700f8ef89e290e4e90ae6adc0908707e0d8c85 578 578 โ—‹ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 f5700f8e 579 579 โ”‚ (no description set) 580 580 โ”‚ -- operation 1663cd1cc445 (2001-02-03 08:05:08) snapshot working copy ··· 583 583 -- operation 8f47435a3990 (2001-02-03 08:05:07) add workspace 'default' 584 584 [EOF] 585 585 ------- stderr ------- 586 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 586 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 587 587 [EOF] 588 588 "#); 589 589 } ··· 637 637 insta::assert_snapshot!(output, @r" 638 638 ------- stderr ------- 639 639 Rebased 2 descendant commits 640 - Selected changes : vruxwmqv 3f0980cb Add file1 641 - Remaining changes: qpvuntsm dff79d19 Add file2 642 - Working copy (@) now at: qpvuntsm dff79d19 Add file2 640 + Selected changes : qpvuntsm 18c85f56 Add file1 641 + Remaining changes: vruxwmqv cbdfd9cf Add file2 642 + Working copy (@) now at: vruxwmqv cbdfd9cf Add file2 643 643 Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) 644 644 Added 0 files, modified 0 files, removed 1 files 645 645 [EOF] ··· 648 648 โ—‹ kkmpptxzrspx false Add file4 649 649 โ—‹ rlvkpnrzqnoo false Add file3 650 650 โ”œโ”€โ•ฎ 651 - โ”‚ @ qpvuntsmwlqt false Add file2 652 - โ—‹ โ”‚ vruxwmqvtpmx false Add file1 651 + โ”‚ @ vruxwmqvtpmx false Add file2 652 + โ—‹ โ”‚ qpvuntsmwlqt false Add file1 653 653 โ”œโ”€โ•ฏ 654 654 โ—† zzzzzzzzzzzz true 655 655 [EOF] ··· 714 714 insta::assert_snapshot!(output, @r" 715 715 ------- stderr ------- 716 716 Rebased 1 descendant commits 717 - Selected changes : royxmykx ad21dad2 Add file1 718 - Remaining changes: kkmpptxz 23a2daac Add file2 719 - Working copy (@) now at: zsuskuln f1fcb7a6 (empty) 2 717 + Selected changes : kkmpptxz cc199567 Add file1 718 + Remaining changes: royxmykx 82a5c527 Add file2 719 + Working copy (@) now at: zsuskuln b7cdcdec (empty) 2 720 720 Parent commit (@-) : qpvuntsm 884fe9b9 (empty) 1 721 - Parent commit (@-) : royxmykx ad21dad2 Add file1 722 - Parent commit (@-) : kkmpptxz 23a2daac Add file2 721 + Parent commit (@-) : kkmpptxz cc199567 Add file1 722 + Parent commit (@-) : royxmykx 82a5c527 Add file2 723 723 [EOF] 724 724 "); 725 725 insta::assert_snapshot!(get_log_output(&work_dir), @r" 726 726 @ zsuskulnrvyr true 2 727 727 โ”œโ”€โ”ฌโ”€โ•ฎ 728 - โ”‚ โ”‚ โ—‹ kkmpptxzrspx false Add file2 729 - โ”‚ โ—‹ โ”‚ royxmykxtrkr false Add file1 728 + โ”‚ โ”‚ โ—‹ royxmykxtrkr false Add file2 729 + โ”‚ โ—‹ โ”‚ kkmpptxzrspx false Add file1 730 730 โ”‚ โ”œโ”€โ•ฏ 731 731 โ—‹ โ”‚ qpvuntsmwlqt true 1 732 732 โ”œโ”€โ•ฏ ··· 793 793 let output = work_dir.run_jj(["split"]); 794 794 insta::assert_snapshot!(output, @r" 795 795 ------- stderr ------- 796 - Selected changes : rlvkpnrz 1ff7a783 (no description set) 797 - Remaining changes: qpvuntsm 429f292f (no description set) 798 - Working copy (@) now at: qpvuntsm 429f292f (no description set) 799 - Parent commit (@-) : rlvkpnrz 1ff7a783 (no description set) 796 + Selected changes : qpvuntsm c664a51b (no description set) 797 + Remaining changes: rlvkpnrz 7e5d65b1 (no description set) 798 + Working copy (@) now at: rlvkpnrz 7e5d65b1 (no description set) 799 + Parent commit (@-) : qpvuntsm c664a51b (no description set) 800 800 [EOF] 801 801 "); 802 802 ··· 824 824 825 825 let output = work_dir.run_jj(["log", "--summary"]); 826 826 insta::assert_snapshot!(output, @r" 827 - @ qpvuntsm test.user@example.com 2001-02-03 08:05:08 429f292f 827 + @ rlvkpnrz test.user@example.com 2001-02-03 08:05:08 7e5d65b1 828 828 โ”‚ (no description set) 829 829 โ”‚ A file2 830 - โ—‹ rlvkpnrz test.user@example.com 2001-02-03 08:05:08 1ff7a783 830 + โ—‹ qpvuntsm test.user@example.com 2001-02-03 08:05:08 c664a51b 831 831 โ”‚ (no description set) 832 832 โ”‚ A file1 833 833 โ—† zzzzzzzz root() 00000000 ··· 869 869 let output = work_dir.run_jj(["split", "-i", "file1", "file2"]); 870 870 insta::assert_snapshot!(output, @r" 871 871 ------- stderr ------- 872 - Selected changes : kkmpptxz 0a5bea34 (no description set) 873 - Remaining changes: rlvkpnrz 7326e6fd (no description set) 874 - Working copy (@) now at: rlvkpnrz 7326e6fd (no description set) 875 - Parent commit (@-) : kkmpptxz 0a5bea34 (no description set) 872 + Selected changes : rlvkpnrz cdc9960a (no description set) 873 + Remaining changes: kkmpptxz 7255f070 (no description set) 874 + Working copy (@) now at: kkmpptxz 7255f070 (no description set) 875 + Parent commit (@-) : rlvkpnrz cdc9960a (no description set) 876 876 [EOF] 877 877 "); 878 878 ··· 889 889 890 890 let output = work_dir.run_jj(["log", "--summary"]); 891 891 insta::assert_snapshot!(output, @r" 892 - @ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 7326e6fd 892 + @ kkmpptxz test.user@example.com 2001-02-03 08:05:09 7255f070 893 893 โ”‚ (no description set) 894 894 โ”‚ M file2 895 895 โ”‚ M file3 896 - โ—‹ kkmpptxz test.user@example.com 2001-02-03 08:05:09 0a5bea34 896 + โ—‹ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 cdc9960a 897 897 โ”‚ (no description set) 898 898 โ”‚ A file1 899 899 โ—‹ qpvuntsm test.user@example.com 2001-02-03 08:05:08 ff687a2f ··· 947 947 main_dir.run_jj(["split", "file2"]).success(); 948 948 // The working copy for both workspaces will be the second split commit. 949 949 insta::assert_snapshot!(get_workspace_log_output(&main_dir), @r" 950 - @ qpvuntsmwlqt default@ second@ second-commit 951 - โ—‹ royxmykxtrkr first-commit 950 + @ royxmykxtrkr default@ second@ second-commit 951 + โ—‹ qpvuntsmwlqt first-commit 952 952 โ—† zzzzzzzzzzzz 953 953 [EOF] 954 954 "); ··· 962 962 .unwrap(); 963 963 main_dir.run_jj(["split", "file2", "--parallel"]).success(); 964 964 insta::assert_snapshot!(get_workspace_log_output(&main_dir), @r" 965 - @ qpvuntsmwlqt default@ second@ second-commit 966 - โ”‚ โ—‹ yostqsxwqrlt first-commit 965 + @ yostqsxwqrlt default@ second@ second-commit 966 + โ”‚ โ—‹ qpvuntsmwlqt first-commit 967 967 โ”œโ”€โ•ฏ 968 968 โ—† zzzzzzzzzzzz 969 969 [EOF] ··· 1006 1006 main_dir.run_jj(["split", "file2"]).success(); 1007 1007 // Only the working copy commit for the default workspace changes. 1008 1008 insta::assert_snapshot!(get_workspace_log_output(&main_dir), @r" 1009 - @ qpvuntsmwlqt default@ second-commit 1010 - โ—‹ mzvwutvlkqwt first-commit 1009 + @ mzvwutvlkqwt default@ second-commit 1010 + โ—‹ qpvuntsmwlqt first-commit 1011 1011 โ”‚ โ—‹ pmmvwywvzvvn second@ 1012 1012 โ”œโ”€โ•ฏ 1013 1013 โ—† zzzzzzzzzzzz ··· 1023 1023 .unwrap(); 1024 1024 main_dir.run_jj(["split", "file2", "--parallel"]).success(); 1025 1025 insta::assert_snapshot!(get_workspace_log_output(&main_dir), @r" 1026 - @ qpvuntsmwlqt default@ second-commit 1027 - โ”‚ โ—‹ vruxwmqvtpmx first-commit 1026 + @ vruxwmqvtpmx default@ second-commit 1027 + โ”‚ โ—‹ qpvuntsmwlqt first-commit 1028 1028 โ”œโ”€โ•ฏ 1029 1029 โ”‚ โ—‹ pmmvwywvzvvn second@ 1030 1030 โ”œโ”€โ•ฏ ··· 1064 1064 let output = work_dir.run_jj(["split", "file1"]); 1065 1065 insta::assert_snapshot!(output, @r#" 1066 1066 ------- stderr ------- 1067 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 1068 - Selected changes : kkmpptxz 530f78ed part 1 1069 - Remaining changes: qpvuntsm 88189e08 part 2 1070 - Working copy (@) now at: qpvuntsm 88189e08 part 2 1071 - Parent commit (@-) : kkmpptxz 530f78ed part 1 1067 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 1068 + Selected changes : qpvuntsm c7f7b14b part 1 1069 + Remaining changes: kkmpptxz ac33a5a9 part 2 1070 + Working copy (@) now at: kkmpptxz ac33a5a9 part 2 1071 + Parent commit (@-) : qpvuntsm c7f7b14b part 1 1072 1072 [EOF] 1073 1073 "#); 1074 1074 ··· 1097 1097 JJ: Lines starting with "JJ:" (like this one) will be removed. 1098 1098 "#); 1099 1099 insta::assert_snapshot!(get_log_output(&work_dir), @r#" 1100 - @ qpvuntsmwlqt false part 2 1101 - โ—‹ kkmpptxzrspx false part 1 1100 + @ kkmpptxzrspx false part 2 1101 + โ—‹ qpvuntsmwlqt false part 1 1102 1102 โ—† zzzzzzzzzzzz true 1103 1103 [EOF] 1104 1104 ------- stderr ------- 1105 - Warning: Deprecated config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 1105 + Warning: Deprecated user-level config: ui.default-description is updated to template-aliases.default_commit_description = '"\n\nTESTED=TODO\n"' 1106 1106 [EOF] 1107 1107 "#); 1108 1108 } ··· 1120 1120 let output = work_dir.run_jj(["split", "-m", "fix in file1", "file1"]); 1121 1121 insta::assert_snapshot!(output, @r" 1122 1122 ------- stderr ------- 1123 - Selected changes : kkmpptxz b246503a fix in file1 1124 - Remaining changes: qpvuntsm e05b5012 my feature 1125 - Working copy (@) now at: qpvuntsm e05b5012 my feature 1126 - Parent commit (@-) : kkmpptxz b246503a fix in file1 1123 + Selected changes : qpvuntsm f2a70519 fix in file1 1124 + Remaining changes: kkmpptxz cac11766 my feature 1125 + Working copy (@) now at: kkmpptxz cac11766 my feature 1126 + Parent commit (@-) : qpvuntsm f2a70519 fix in file1 1127 1127 [EOF] 1128 1128 "); 1129 1129 1130 1130 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1131 - @ qpvuntsmwlqt false my feature 1132 - โ—‹ kkmpptxzrspx false fix in file1 1131 + @ kkmpptxzrspx false my feature 1132 + โ—‹ qpvuntsmwlqt false fix in file1 1133 1133 โ—† zzzzzzzzzzzz true 1134 1134 [EOF] 1135 1135 "); ··· 1146 1146 ]); 1147 1147 insta::assert_snapshot!(output, @r" 1148 1148 ------- stderr ------- 1149 - Selected changes : royxmykx 87fbb488 fix in file1 1150 - Remaining changes: qpvuntsm fb598346 my feature 1151 - Working copy (@) now at: qpvuntsm fb598346 my feature 1152 - Parent commit (@-) : royxmykx 87fbb488 fix in file1 1149 + Selected changes : qpvuntsm d01cf12d fix in file1 1150 + Remaining changes: royxmykx b1556ed9 my feature 1151 + Working copy (@) now at: royxmykx b1556ed9 my feature 1152 + Parent commit (@-) : qpvuntsm d01cf12d fix in file1 1153 1153 [EOF] 1154 1154 "); 1155 1155 1156 1156 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1157 - @ qpvuntsmwlqt false my feature 1158 - โ—‹ royxmykxtrkr false fix in file1 1157 + @ royxmykxtrkr false my feature 1158 + โ—‹ qpvuntsmwlqt false fix in file1 1159 1159 โ”‚ 1160 1160 โ”‚ CC: test.user@example.com 1161 1161 โ—† zzzzzzzzzzzz true ··· 1470 1470 .unwrap(); 1471 1471 let output = main_dir.run_jj(["split", "file2"]); 1472 1472 match bookmark_behavior { 1473 - BookmarkBehavior::Default | BookmarkBehavior::LeaveBookmarkWithTarget => { 1473 + BookmarkBehavior::LeaveBookmarkWithTarget => { 1474 1474 insta::allow_duplicates! { 1475 1475 insta::assert_snapshot!(output, @r#" 1476 1476 ------- stderr ------- 1477 - Selected changes : mzvwutvl ac5cf500 first-commit 1478 - Remaining changes: qpvuntsm a13c536a "*le-signet*" | second-commit 1479 - Working copy (@) now at: qpvuntsm a13c536a "*le-signet*" | second-commit 1480 - Parent commit (@-) : mzvwutvl ac5cf500 first-commit 1477 + Selected changes : qpvuntsm a481fe8a "*le-signet*" | first-commit 1478 + Remaining changes: mzvwutvl 5f597a6e second-commit 1479 + Working copy (@) now at: mzvwutvl 5f597a6e second-commit 1480 + Parent commit (@-) : qpvuntsm a481fe8a "*le-signet*" | first-commit 1481 1481 [EOF] 1482 1482 "#); 1483 1483 } 1484 1484 insta::allow_duplicates! { 1485 1485 insta::assert_snapshot!(get_log_output(&main_dir), @r#" 1486 - @ qpvuntsmwlqt false "*le-signet*" second-commit 1487 - โ—‹ mzvwutvlkqwt false first-commit 1486 + @ mzvwutvlkqwt false second-commit 1487 + โ—‹ qpvuntsmwlqt false "*le-signet*" first-commit 1488 1488 โ—† zzzzzzzzzzzz true 1489 1489 [EOF] 1490 1490 "#); 1491 1491 } 1492 1492 } 1493 - BookmarkBehavior::MoveBookmarkToChild => { 1493 + BookmarkBehavior::Default | BookmarkBehavior::MoveBookmarkToChild => { 1494 1494 insta::allow_duplicates! { 1495 1495 insta::assert_snapshot!(output, @r#" 1496 1496 ------- stderr ------- ··· 1521 1521 .unwrap(); 1522 1522 main_dir.run_jj(["split", "file2", "--parallel"]).success(); 1523 1523 match bookmark_behavior { 1524 - BookmarkBehavior::Default | BookmarkBehavior::LeaveBookmarkWithTarget => { 1524 + BookmarkBehavior::LeaveBookmarkWithTarget => { 1525 1525 insta::allow_duplicates! { 1526 1526 insta::assert_snapshot!(get_log_output(&main_dir), @r#" 1527 - @ qpvuntsmwlqt false "*le-signet*" second-commit 1528 - โ”‚ โ—‹ vruxwmqvtpmx false first-commit 1527 + @ vruxwmqvtpmx false second-commit 1528 + โ”‚ โ—‹ qpvuntsmwlqt false "*le-signet*" first-commit 1529 1529 โ”œโ”€โ•ฏ 1530 1530 โ—† zzzzzzzzzzzz true 1531 1531 [EOF] 1532 1532 "#); 1533 1533 } 1534 1534 } 1535 - BookmarkBehavior::MoveBookmarkToChild => { 1535 + BookmarkBehavior::Default | BookmarkBehavior::MoveBookmarkToChild => { 1536 1536 insta::allow_duplicates! { 1537 1537 insta::assert_snapshot!(get_log_output(&main_dir), @r#" 1538 1538 @ vruxwmqvtpmx false "*le-signet*" second-commit
-775
cli/tests/test_squash_command.rs
··· 746 746 } 747 747 748 748 #[test] 749 - fn test_squash_working_copy_restore_descendants() { 750 - let test_env = TestEnvironment::default(); 751 - test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 752 - let work_dir = test_env.work_dir("repo"); 753 - 754 - // Create history like this: 755 - // Y 756 - // | 757 - // B X@ 758 - // |/ 759 - // A 760 - // 761 - // Each commit adds a file named the same as the commit 762 - let create_commit = |name: &str| { 763 - work_dir 764 - .run_jj(["bookmark", "create", "-r@", name]) 765 - .success(); 766 - work_dir.write_file(name, format!("test {name}\n")); 767 - }; 768 - 769 - create_commit("a"); 770 - work_dir.run_jj(["new"]).success(); 771 - create_commit("b"); 772 - work_dir.run_jj(["new", "a"]).success(); 773 - create_commit("x"); 774 - work_dir.run_jj(["new"]).success(); 775 - create_commit("y"); 776 - work_dir.run_jj(["edit", "x"]).success(); 777 - 778 - let template = r#"separate( 779 - " ", 780 - commit_id.short(), 781 - bookmarks, 782 - description, 783 - if(empty, "(empty)") 784 - )"#; 785 - let run_log = || work_dir.run_jj(["log", "-r=::", "--summary", "-T", template]); 786 - 787 - // Verify the setup 788 - insta::assert_snapshot!(run_log(), @r" 789 - โ—‹ 3f45d7a3ae69 y 790 - โ”‚ A y 791 - @ 5b4046443e64 x 792 - โ”‚ A x 793 - โ”‚ โ—‹ b1e1eea2f666 b 794 - โ”œโ”€โ•ฏ A b 795 - โ—‹ 7468364c89fc a 796 - โ”‚ A a 797 - โ—† 000000000000 (empty) 798 - [EOF] 799 - "); 800 - let output = work_dir.run_jj(["file", "list", "-r=a"]); 801 - insta::assert_snapshot!(output, @r" 802 - a 803 - [EOF] 804 - "); 805 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 806 - insta::assert_snapshot!(output, @r" 807 - a 808 - b 809 - [EOF] 810 - "); 811 - let output = work_dir.run_jj(["file", "list"]); 812 - insta::assert_snapshot!(output, @r" 813 - a 814 - x 815 - [EOF] 816 - "); 817 - let output = work_dir.run_jj(["file", "list", "-r=y"]); 818 - insta::assert_snapshot!(output, @r" 819 - a 820 - x 821 - y 822 - [EOF] 823 - "); 824 - 825 - let output = work_dir.run_jj(["squash", "--restore-descendants"]); 826 - insta::assert_snapshot!(output, @r" 827 - ------- stderr ------- 828 - Rebased 2 descendant commits (while preserving their content) 829 - Working copy (@) now at: kxryzmor 7ec5499d (empty) (no description set) 830 - Parent commit (@-) : qpvuntsm 1c6a069e a x | (no description set) 831 - [EOF] 832 - "); 833 - insta::assert_snapshot!(run_log(), @r" 834 - @ 7ec5499d9141 (empty) 835 - โ”‚ โ—‹ ddfef0b279f8 y 836 - โ”œโ”€โ•ฏ A y 837 - โ”‚ โ—‹ 640ba5e85507 b 838 - โ”œโ”€โ•ฏ A b 839 - โ”‚ D x 840 - โ—‹ 1c6a069ec7e3 a x 841 - โ”‚ A a 842 - โ”‚ A x 843 - โ—† 000000000000 (empty) 844 - [EOF] 845 - "); 846 - 847 - let output = work_dir.run_jj(["diff", "--summary"]); 848 - // The current commit becomes empty. 849 - insta::assert_snapshot!(output, @""); 850 - // Should coincide with the working copy commit before 851 - let output = work_dir.run_jj(["file", "list", "-r=a"]); 852 - insta::assert_snapshot!(output, @r" 853 - a 854 - x 855 - [EOF] 856 - "); 857 - // Commit b should be the same as before 858 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 859 - insta::assert_snapshot!(output, @r" 860 - a 861 - b 862 - [EOF] 863 - "); 864 - let output = work_dir.run_jj(["file", "list", "-r=y"]); 865 - insta::assert_snapshot!(output, @r" 866 - a 867 - x 868 - y 869 - [EOF] 870 - "); 871 - } 872 - 873 - #[test] 874 - fn test_squash_from_to_restore_descendants() { 875 - let test_env = TestEnvironment::default(); 876 - test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 877 - let work_dir = test_env.work_dir("repo"); 878 - 879 - // Create history like this: 880 - // F 881 - // |\ 882 - // E C 883 - // | | 884 - // D B 885 - // |/ 886 - // A 887 - // 888 - // Each commit adds a file named the same as the commit 889 - let create_commit = |name: &str| { 890 - work_dir 891 - .run_jj(["bookmark", "create", "-r@", name]) 892 - .success(); 893 - work_dir.write_file(name, format!("test {name}\n")); 894 - }; 895 - 896 - create_commit("a"); 897 - work_dir.run_jj(["new"]).success(); 898 - create_commit("b"); 899 - work_dir.run_jj(["new"]).success(); 900 - create_commit("c"); 901 - work_dir.run_jj(["new", "a"]).success(); 902 - create_commit("d"); 903 - work_dir.run_jj(["new"]).success(); 904 - create_commit("e"); 905 - work_dir.run_jj(["new", "e", "c"]).success(); 906 - create_commit("f"); 907 - 908 - let template = r#"separate( 909 - " ", 910 - commit_id.short(), 911 - bookmarks, 912 - description, 913 - if(empty, "(empty)") 914 - )"#; 915 - let run_log = || work_dir.run_jj(["log", "-r=::", "--summary", "-T", template]); 916 - 917 - // ========== Part 1 ========= 918 - // Verify the setup 919 - insta::assert_snapshot!(run_log(), @r" 920 - @ 42acd0537c88 f 921 - โ”œโ”€โ•ฎ A f 922 - โ”‚ โ—‹ 4fb9706b0f47 c 923 - โ”‚ โ”‚ A c 924 - โ”‚ โ—‹ b1e1eea2f666 b 925 - โ”‚ โ”‚ A b 926 - โ—‹ โ”‚ b4e3197108ba e 927 - โ”‚ โ”‚ A e 928 - โ—‹ โ”‚ d707102f499f d 929 - โ”œโ”€โ•ฏ A d 930 - โ—‹ 7468364c89fc a 931 - โ”‚ A a 932 - โ—† 000000000000 (empty) 933 - [EOF] 934 - "); 935 - let beginning = work_dir.current_operation_id(); 936 - test_env.advance_test_rng_seed_to_multiple_of(200_000); 937 - 938 - // Squash without --restore-descendants for comparison 939 - work_dir 940 - .run_jj(["operation", "restore", &beginning]) 941 - .success(); 942 - let output = work_dir.run_jj(["squash", "--from=b", "--into=d"]); 943 - insta::assert_snapshot!(output, @r" 944 - ------- stderr ------- 945 - Rebased 3 descendant commits 946 - Working copy (@) now at: kpqxywon e462100a f | (no description set) 947 - Parent commit (@-) : yostqsxw 6944fd03 e | (no description set) 948 - Parent commit (@-) : mzvwutvl 6cd5d5c1 c | (no description set) 949 - [EOF] 950 - "); 951 - insta::assert_snapshot!(run_log(), @r" 952 - @ e462100ae7c3 f 953 - โ”œโ”€โ•ฎ A f 954 - โ”‚ โ—‹ 6cd5d5c1daf7 c 955 - โ”‚ โ”‚ A c 956 - โ—‹ โ”‚ 6944fd03dc5d e 957 - โ”‚ โ”‚ A e 958 - โ—‹ โ”‚ 1befcf027d1b d 959 - โ”œโ”€โ•ฏ A b 960 - โ”‚ A d 961 - โ—‹ 7468364c89fc a b 962 - โ”‚ A a 963 - โ—† 000000000000 (empty) 964 - [EOF] 965 - "); 966 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 967 - insta::assert_snapshot!(output, @r" 968 - a 969 - b 970 - d 971 - [EOF] 972 - "); 973 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 974 - insta::assert_snapshot!(output, @r" 975 - a 976 - c 977 - [EOF] 978 - "); 979 - let output = work_dir.run_jj(["file", "list", "-r=e"]); 980 - insta::assert_snapshot!(output, @r" 981 - a 982 - b 983 - d 984 - e 985 - [EOF] 986 - "); 987 - let output = work_dir.run_jj(["file", "list", "-r=f"]); 988 - insta::assert_snapshot!(output, @r" 989 - a 990 - b 991 - c 992 - d 993 - e 994 - f 995 - [EOF] 996 - "); 997 - 998 - // --restore-descendants 999 - work_dir 1000 - .run_jj(["operation", "restore", &beginning]) 1001 - .success(); 1002 - let output = work_dir.run_jj(["squash", "--from=b", "--into=d", "--restore-descendants"]); 1003 - insta::assert_snapshot!(output, @r" 1004 - ------- stderr ------- 1005 - Rebased 3 descendant commits (while preserving their content) 1006 - Working copy (@) now at: kpqxywon 1d64ccbf f | (no description set) 1007 - Parent commit (@-) : yostqsxw cb90d752 e | (no description set) 1008 - Parent commit (@-) : mzvwutvl 4e6702ae c | (no description set) 1009 - [EOF] 1010 - "); 1011 - // `d`` becomes the same as in the above example, 1012 - // but `c` does not lose file `b` and `e` still does not contain file `b` 1013 - // regardless of what happened to their parents. 1014 - insta::assert_snapshot!(run_log(), @r" 1015 - @ 1d64ccbf4608 f 1016 - โ”œโ”€โ•ฎ A f 1017 - โ”‚ โ—‹ 4e6702ae494c c 1018 - โ”‚ โ”‚ A b 1019 - โ”‚ โ”‚ A c 1020 - โ—‹ โ”‚ cb90d75271b4 e 1021 - โ”‚ โ”‚ D b 1022 - โ”‚ โ”‚ A e 1023 - โ—‹ โ”‚ 853ea07451aa d 1024 - โ”œโ”€โ•ฏ A b 1025 - โ”‚ A d 1026 - โ—‹ 7468364c89fc a b 1027 - โ”‚ A a 1028 - โ—† 000000000000 (empty) 1029 - [EOF] 1030 - "); 1031 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1032 - insta::assert_snapshot!(output, @r" 1033 - a 1034 - b 1035 - d 1036 - [EOF] 1037 - "); 1038 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1039 - insta::assert_snapshot!(output, @r" 1040 - a 1041 - b 1042 - c 1043 - [EOF] 1044 - "); 1045 - let output = work_dir.run_jj(["file", "list", "-r=e"]); 1046 - insta::assert_snapshot!(output, @r" 1047 - a 1048 - d 1049 - e 1050 - [EOF] 1051 - "); 1052 - let output = work_dir.run_jj(["file", "list", "-r=f"]); 1053 - insta::assert_snapshot!(output, @r" 1054 - a 1055 - b 1056 - c 1057 - d 1058 - e 1059 - f 1060 - [EOF] 1061 - "); 1062 - 1063 - // --restore-descendants works with --keep-emptied, same result except for 1064 - // leaving an empty commit 1065 - work_dir 1066 - .run_jj(["operation", "restore", &beginning]) 1067 - .success(); 1068 - let output = work_dir.run_jj([ 1069 - "squash", 1070 - "--from=b", 1071 - "--into=d", 1072 - "--restore-descendants", 1073 - "--keep-emptied", 1074 - ]); 1075 - insta::assert_snapshot!(output, @r" 1076 - ------- stderr ------- 1077 - Rebased 3 descendant commits (while preserving their content) 1078 - Working copy (@) now at: kpqxywon 3c13920f f | (no description set) 1079 - Parent commit (@-) : yostqsxw aa73012d e | (no description set) 1080 - Parent commit (@-) : mzvwutvl d323deaa c | (no description set) 1081 - [EOF] 1082 - "); 1083 - // `d`` becomes the same as in the above example, 1084 - // but `c` does not lose file `b` and `e` still does not contain file `b` 1085 - // regardless of what happened to their parents. 1086 - insta::assert_snapshot!(run_log(), @r" 1087 - @ 3c13920f1e9a f 1088 - โ”œโ”€โ•ฎ A f 1089 - โ”‚ โ—‹ d323deaa04c2 c 1090 - โ”‚ โ”‚ A b 1091 - โ”‚ โ”‚ A c 1092 - โ”‚ โ—‹ a55451e8808f b (empty) 1093 - โ—‹ โ”‚ aa73012df9cd e 1094 - โ”‚ โ”‚ D b 1095 - โ”‚ โ”‚ A e 1096 - โ—‹ โ”‚ d00e73142243 d 1097 - โ”œโ”€โ•ฏ A b 1098 - โ”‚ A d 1099 - โ—‹ 7468364c89fc a 1100 - โ”‚ A a 1101 - โ—† 000000000000 (empty) 1102 - [EOF] 1103 - "); 1104 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1105 - insta::assert_snapshot!(output, @r" 1106 - a 1107 - b 1108 - d 1109 - [EOF] 1110 - "); 1111 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1112 - insta::assert_snapshot!(output, @r" 1113 - a 1114 - b 1115 - c 1116 - [EOF] 1117 - "); 1118 - let output = work_dir.run_jj(["file", "list", "-r=e"]); 1119 - insta::assert_snapshot!(output, @r" 1120 - a 1121 - d 1122 - e 1123 - [EOF] 1124 - "); 1125 - 1126 - // ========== Part 2 ========= 1127 - // Reminder of the setup 1128 - test_env.advance_test_rng_seed_to_multiple_of(200_000); 1129 - work_dir 1130 - .run_jj(["operation", "restore", &beginning]) 1131 - .success(); 1132 - insta::assert_snapshot!(run_log(), @r" 1133 - @ 42acd0537c88 f 1134 - โ”œโ”€โ•ฎ A f 1135 - โ”‚ โ—‹ 4fb9706b0f47 c 1136 - โ”‚ โ”‚ A c 1137 - โ”‚ โ—‹ b1e1eea2f666 b 1138 - โ”‚ โ”‚ A b 1139 - โ—‹ โ”‚ b4e3197108ba e 1140 - โ”‚ โ”‚ A e 1141 - โ—‹ โ”‚ d707102f499f d 1142 - โ”œโ”€โ•ฏ A d 1143 - โ—‹ 7468364c89fc a 1144 - โ”‚ A a 1145 - โ—† 000000000000 (empty) 1146 - [EOF] 1147 - "); 1148 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1149 - insta::assert_snapshot!(output, @r" 1150 - a 1151 - b 1152 - c 1153 - [EOF] 1154 - "); 1155 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1156 - insta::assert_snapshot!(output, @r" 1157 - a 1158 - d 1159 - [EOF] 1160 - "); 1161 - 1162 - // --restore-descendants works when squashing from parent to child 1163 - work_dir 1164 - .run_jj(["operation", "restore", &beginning]) 1165 - .success(); 1166 - let output = work_dir.run_jj(["squash", "--from=a", "--into=b", "--restore-descendants"]); 1167 - insta::assert_snapshot!(output, @r" 1168 - ------- stderr ------- 1169 - Rebased 2 descendant commits (while preserving their content) 1170 - Working copy (@) now at: kpqxywon 7fa445c9 f | (no description set) 1171 - Parent commit (@-) : yostqsxw 102e6106 e | (no description set) 1172 - Parent commit (@-) : mzvwutvl a2ff7c27 c | (no description set) 1173 - [EOF] 1174 - "); 1175 - insta::assert_snapshot!(run_log(), @r" 1176 - @ 7fa445c9e606 f 1177 - โ”œโ”€โ•ฎ A f 1178 - โ”‚ โ—‹ a2ff7c27dbba c 1179 - โ”‚ โ”‚ A c 1180 - โ”‚ โ—‹ 2bf81678391c b 1181 - โ”‚ โ”‚ A a 1182 - โ”‚ โ”‚ A b 1183 - โ—‹ โ”‚ 102e61065eb2 e 1184 - โ”‚ โ”‚ A e 1185 - โ—‹ โ”‚ 7b1493a2027e d 1186 - โ”œโ”€โ•ฏ A a 1187 - โ”‚ A d 1188 - โ—† 000000000000 a (empty) 1189 - [EOF] 1190 - "); 1191 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1192 - insta::assert_snapshot!(output, @r" 1193 - a 1194 - b 1195 - [EOF] 1196 - "); 1197 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1198 - insta::assert_snapshot!(output, @r" 1199 - a 1200 - b 1201 - c 1202 - [EOF] 1203 - "); 1204 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1205 - insta::assert_snapshot!(output, @r" 1206 - a 1207 - d 1208 - [EOF] 1209 - "); 1210 - 1211 - // --restore-descendants --keep-emptied works when squashing from parent to 1212 - // child 1213 - work_dir 1214 - .run_jj(["operation", "restore", &beginning]) 1215 - .success(); 1216 - let output = work_dir.run_jj([ 1217 - "squash", 1218 - "--from=a", 1219 - "--into=b", 1220 - "--restore-descendants", 1221 - "--keep-emptied", 1222 - ]); 1223 - insta::assert_snapshot!(output, @r" 1224 - ------- stderr ------- 1225 - Rebased 2 descendant commits (while preserving their content) 1226 - Working copy (@) now at: kpqxywon 30c1ec1b f | (no description set) 1227 - Parent commit (@-) : yostqsxw c20a2a7a e | (no description set) 1228 - Parent commit (@-) : mzvwutvl 601223f5 c | (no description set) 1229 - [EOF] 1230 - "); 1231 - insta::assert_snapshot!(run_log(), @r" 1232 - @ 30c1ec1b6264 f 1233 - โ”œโ”€โ•ฎ A f 1234 - โ”‚ โ—‹ 601223f5faa8 c 1235 - โ”‚ โ”‚ A c 1236 - โ”‚ โ—‹ 28223a4af36c b 1237 - โ”‚ โ”‚ A a 1238 - โ”‚ โ”‚ A b 1239 - โ—‹ โ”‚ c20a2a7a24ba e 1240 - โ”‚ โ”‚ A e 1241 - โ—‹ โ”‚ a224ba6ebde8 d 1242 - โ”œโ”€โ•ฏ A a 1243 - โ”‚ A d 1244 - โ—‹ 367fe826e43e a (empty) 1245 - โ—† 000000000000 (empty) 1246 - [EOF] 1247 - "); 1248 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1249 - insta::assert_snapshot!(output, @r" 1250 - a 1251 - b 1252 - [EOF] 1253 - "); 1254 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1255 - insta::assert_snapshot!(output, @r" 1256 - a 1257 - b 1258 - c 1259 - [EOF] 1260 - "); 1261 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1262 - insta::assert_snapshot!(output, @r" 1263 - a 1264 - d 1265 - [EOF] 1266 - "); 1267 - 1268 - // --restore-descendants works when squashing from child to parent 1269 - work_dir 1270 - .run_jj(["operation", "restore", &beginning]) 1271 - .success(); 1272 - let output = work_dir.run_jj(["squash", "--from=b", "--into=a", "--restore-descendants"]); 1273 - insta::assert_snapshot!(output, @r" 1274 - ------- stderr ------- 1275 - Rebased 4 descendant commits (while preserving their content) 1276 - Working copy (@) now at: kpqxywon 6ad1c62a f | (no description set) 1277 - Parent commit (@-) : yostqsxw e259f026 e | (no description set) 1278 - Parent commit (@-) : mzvwutvl 36192c59 c | (no description set) 1279 - [EOF] 1280 - "); 1281 - insta::assert_snapshot!(run_log(), @r" 1282 - @ 6ad1c62aec5b f 1283 - โ”œโ”€โ•ฎ A b 1284 - โ”‚ โ”‚ A f 1285 - โ”‚ โ—‹ 36192c59f1e9 c 1286 - โ”‚ โ”‚ A c 1287 - โ—‹ โ”‚ e259f02633ca e 1288 - โ”‚ โ”‚ A e 1289 - โ—‹ โ”‚ 92943f1c8204 d 1290 - โ”œโ”€โ•ฏ D b 1291 - โ”‚ A d 1292 - โ—‹ 59aac8514774 a b 1293 - โ”‚ A a 1294 - โ”‚ A b 1295 - โ—† 000000000000 (empty) 1296 - [EOF] 1297 - "); 1298 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1299 - insta::assert_snapshot!(output, @r" 1300 - a 1301 - b 1302 - [EOF] 1303 - "); 1304 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1305 - insta::assert_snapshot!(output, @r" 1306 - a 1307 - b 1308 - c 1309 - [EOF] 1310 - "); 1311 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1312 - insta::assert_snapshot!(output, @r" 1313 - a 1314 - d 1315 - [EOF] 1316 - "); 1317 - 1318 - // same test, but with --keep-emptied 1319 - work_dir 1320 - .run_jj(["operation", "restore", &beginning]) 1321 - .success(); 1322 - let output = work_dir.run_jj([ 1323 - "squash", 1324 - "--from=b", 1325 - "--into=a", 1326 - "--keep-emptied", 1327 - "--restore-descendants", 1328 - ]); 1329 - insta::assert_snapshot!(output, @r" 1330 - ------- stderr ------- 1331 - Rebased 5 descendant commits (while preserving their content) 1332 - Working copy (@) now at: kpqxywon 6eadede0 f | (no description set) 1333 - Parent commit (@-) : yostqsxw 97233b50 e | (no description set) 1334 - Parent commit (@-) : mzvwutvl 5b2d6858 c | (no description set) 1335 - [EOF] 1336 - "); 1337 - // BUG! b should now be empty! 1338 - insta::assert_snapshot!(run_log(), @r" 1339 - @ 6eadede086b1 f 1340 - โ”œโ”€โ•ฎ A b 1341 - โ”‚ โ”‚ A f 1342 - โ”‚ โ—‹ 5b2d685868b7 c 1343 - โ”‚ โ”‚ A b 1344 - โ”‚ โ”‚ A c 1345 - โ”‚ โ—‹ 904dac9cd09e b 1346 - โ”‚ โ”‚ D b 1347 - โ—‹ โ”‚ 97233b506c11 e 1348 - โ”‚ โ”‚ A e 1349 - โ—‹ โ”‚ 8cbe1a629aed d 1350 - โ”œโ”€โ•ฏ D b 1351 - โ”‚ A d 1352 - โ—‹ c1fbbbe74a28 a 1353 - โ”‚ A a 1354 - โ”‚ A b 1355 - โ—† 000000000000 (empty) 1356 - [EOF] 1357 - "); 1358 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1359 - insta::assert_snapshot!(output, @r" 1360 - a 1361 - [EOF] 1362 - "); 1363 - let output = work_dir.run_jj(["file", "list", "-r=c"]); 1364 - insta::assert_snapshot!(output, @r" 1365 - a 1366 - b 1367 - c 1368 - [EOF] 1369 - "); 1370 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1371 - insta::assert_snapshot!(output, @r" 1372 - a 1373 - d 1374 - [EOF] 1375 - "); 1376 - 1377 - // ========== Part 3 ========= 1378 - // Reminder of the setup 1379 - test_env.advance_test_rng_seed_to_multiple_of(200_000); 1380 - work_dir 1381 - .run_jj(["operation", "restore", &beginning]) 1382 - .success(); 1383 - insta::assert_snapshot!(run_log(), @r" 1384 - @ 42acd0537c88 f 1385 - โ”œโ”€โ•ฎ A f 1386 - โ”‚ โ—‹ 4fb9706b0f47 c 1387 - โ”‚ โ”‚ A c 1388 - โ”‚ โ—‹ b1e1eea2f666 b 1389 - โ”‚ โ”‚ A b 1390 - โ—‹ โ”‚ b4e3197108ba e 1391 - โ”‚ โ”‚ A e 1392 - โ—‹ โ”‚ d707102f499f d 1393 - โ”œโ”€โ•ฏ A d 1394 - โ—‹ 7468364c89fc a 1395 - โ”‚ A a 1396 - โ—† 000000000000 (empty) 1397 - [EOF] 1398 - "); 1399 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1400 - insta::assert_snapshot!(output, @r" 1401 - a 1402 - d 1403 - [EOF] 1404 - "); 1405 - let output = work_dir.run_jj(["file", "list", "-r=f"]); 1406 - insta::assert_snapshot!(output, @r" 1407 - a 1408 - b 1409 - c 1410 - d 1411 - e 1412 - f 1413 - [EOF] 1414 - "); 1415 - 1416 - // --restore-descendants works when squashing from grandchild to grandparent 1417 - work_dir 1418 - .run_jj(["operation", "restore", &beginning]) 1419 - .success(); 1420 - let output = work_dir.run_jj(["squash", "--from=e", "--into=a", "--restore-descendants"]); 1421 - insta::assert_snapshot!(output, @r" 1422 - ------- stderr ------- 1423 - Rebased 4 descendant commits (while preserving their content) 1424 - Working copy (@) now at: kpqxywon 6d14c928 f | (no description set) 1425 - Parent commit (@-) : yqosqzyt ab775412 d e | (no description set) 1426 - Parent commit (@-) : mzvwutvl 175aa1f2 c | (no description set) 1427 - [EOF] 1428 - "); 1429 - insta::assert_snapshot!(run_log(), @r" 1430 - @ 6d14c928f32e f 1431 - โ”œโ”€โ•ฎ A e 1432 - โ”‚ โ”‚ A f 1433 - โ”‚ โ—‹ 175aa1f28a05 c 1434 - โ”‚ โ”‚ A c 1435 - โ”‚ โ—‹ d1076aeca3e6 b 1436 - โ”‚ โ”‚ A b 1437 - โ”‚ โ”‚ D e 1438 - โ—‹ โ”‚ ab7754126332 d e 1439 - โ”œโ”€โ•ฏ A d 1440 - โ”‚ D e 1441 - โ—‹ 4644e0c16443 a 1442 - โ”‚ A a 1443 - โ”‚ A e 1444 - โ—† 000000000000 (empty) 1445 - [EOF] 1446 - "); 1447 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1448 - insta::assert_snapshot!(output, @r" 1449 - a 1450 - b 1451 - [EOF] 1452 - "); 1453 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1454 - insta::assert_snapshot!(output, @r" 1455 - a 1456 - d 1457 - [EOF] 1458 - "); 1459 - let output = work_dir.run_jj(["file", "list", "-r=f"]); 1460 - insta::assert_snapshot!(output, @r" 1461 - a 1462 - b 1463 - c 1464 - d 1465 - e 1466 - f 1467 - [EOF] 1468 - "); 1469 - 1470 - // --restore-descendants works when squashing from grandparent to grandchild 1471 - work_dir 1472 - .run_jj(["operation", "restore", &beginning]) 1473 - .success(); 1474 - let output = work_dir.run_jj(["squash", "--from=a", "--into=e", "--restore-descendants"]); 1475 - insta::assert_snapshot!(output, @r" 1476 - ------- stderr ------- 1477 - Rebased 1 descendant commits (while preserving their content) 1478 - Working copy (@) now at: kpqxywon 94ad7042 f | (no description set) 1479 - Parent commit (@-) : yostqsxw 582d640e e | (no description set) 1480 - Parent commit (@-) : mzvwutvl 2214436c c | (no description set) 1481 - [EOF] 1482 - "); 1483 - insta::assert_snapshot!(run_log(), @r" 1484 - @ 94ad70428c4a f 1485 - โ”œโ”€โ•ฎ A f 1486 - โ”‚ โ—‹ 2214436c3fa7 c 1487 - โ”‚ โ”‚ A c 1488 - โ”‚ โ—‹ a469c893f362 b 1489 - โ”‚ โ”‚ A a 1490 - โ”‚ โ”‚ A b 1491 - โ—‹ โ”‚ 582d640e331f e 1492 - โ”‚ โ”‚ A e 1493 - โ—‹ โ”‚ 93671eb30330 d 1494 - โ”œโ”€โ•ฏ A a 1495 - โ”‚ A d 1496 - โ—† 000000000000 a (empty) 1497 - [EOF] 1498 - "); 1499 - let output = work_dir.run_jj(["file", "list", "-r=b"]); 1500 - insta::assert_snapshot!(output, @r" 1501 - a 1502 - b 1503 - [EOF] 1504 - "); 1505 - let output = work_dir.run_jj(["file", "list", "-r=d"]); 1506 - insta::assert_snapshot!(output, @r" 1507 - a 1508 - d 1509 - [EOF] 1510 - "); 1511 - let output = work_dir.run_jj(["file", "list", "-r=f"]); 1512 - insta::assert_snapshot!(output, @r" 1513 - a 1514 - b 1515 - c 1516 - d 1517 - e 1518 - f 1519 - [EOF] 1520 - "); 1521 - } 1522 - 1523 - #[test] 1524 749 fn test_squash_from_multiple() { 1525 750 let test_env = TestEnvironment::default(); 1526 751 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
+8 -3
docs/releasing.md
··· 13 13 to run something like this: 14 14 15 15 ```shell 16 - root=$(jj log --no-graph -r 'heads(tags(glob:"v*.*.*") & ::trunk())' -T 'commit_id') 17 - gh api "/repos/jj-vcs/jj/compare/$root...main" --paginate \ 18 - | jq -r '.commits[] | select(.author.login | endswith("[bot]") | not) | "* " + .commit.author.name + " (@" + .author.login + ")"' | sort -fu 16 + root=$(jj log --no-graph -r 'heads(tags(glob:"v*.*.*") & ::trunk())' -T commit_id) 17 + filter=' 18 + map(.commits[] | select(.author.login | endswith("[bot]") | not)) 19 + | unique_by(.author.login) 20 + | map("* \(.commit.author.name) (@\(.author.login))")) 21 + | .[] 22 + ' 23 + gh api "/repos/jj-vcs/jj/compare/$root...main" --paginate | jq -sr "$filter" | sort -f 19 24 ``` 20 25 21 26 https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#compare-two-commits
+28 -9
lib/src/config_resolver.rs
··· 27 27 use crate::config::ConfigGetError; 28 28 use crate::config::ConfigLayer; 29 29 use crate::config::ConfigNamePathBuf; 30 + use crate::config::ConfigSource; 30 31 use crate::config::ConfigUpdateError; 31 32 use crate::config::ConfigValue; 32 33 use crate::config::StackedConfig; ··· 367 368 pub fn migrate( 368 369 config: &mut StackedConfig, 369 370 rules: &[ConfigMigrationRule], 370 - ) -> Result<Vec<String>, ConfigMigrateError> { 371 + ) -> Result<Vec<(ConfigSource, String)>, ConfigMigrateError> { 371 372 let mut descriptions = Vec::new(); 372 373 for layer in config.layers_mut() { 373 374 migrate_layer(layer, rules, &mut descriptions) ··· 379 380 fn migrate_layer( 380 381 layer: &mut Arc<ConfigLayer>, 381 382 rules: &[ConfigMigrationRule], 382 - descriptions: &mut Vec<String>, 383 + descriptions: &mut Vec<(ConfigSource, String)>, 383 384 ) -> Result<(), ConfigMigrateLayerError> { 384 385 let rules_to_apply = rules 385 386 .iter() ··· 391 392 let layer_mut = Arc::make_mut(layer); 392 393 for rule in rules_to_apply { 393 394 let desc = rule.apply(layer_mut)?; 394 - descriptions.push(desc); 395 + descriptions.push((layer_mut.source, desc)); 395 396 } 396 397 Ok(()) 397 398 } ··· 862 863 let descriptions = migrate(&mut config, &rules).unwrap(); 863 864 insta::assert_debug_snapshot!(descriptions, @r#" 864 865 [ 865 - "foo.old is renamed to foo.new", 866 - "bar.old is deleted (superseded by baz.new)", 867 - "bar.old is renamed to baz.new", 866 + ( 867 + User, 868 + "foo.old is renamed to foo.new", 869 + ), 870 + ( 871 + User, 872 + "bar.old is deleted (superseded by baz.new)", 873 + ), 874 + ( 875 + User, 876 + "bar.old is renamed to baz.new", 877 + ), 868 878 ] 869 879 "#); 870 880 insta::assert_snapshot!(config.layers()[0].data, @r" ··· 913 923 let descriptions = migrate(&mut config, &rules).unwrap(); 914 924 insta::assert_debug_snapshot!(descriptions, @r#" 915 925 [ 916 - "foo.old is updated to foo.new = ['foo.old #0']", 917 - "bar.old is deleted (superseded by baz.new)", 918 - "bar.old is updated to baz.new = \"bar.old #1 updated\"", 926 + ( 927 + User, 928 + "foo.old is updated to foo.new = ['foo.old #0']", 929 + ), 930 + ( 931 + User, 932 + "bar.old is deleted (superseded by baz.new)", 933 + ), 934 + ( 935 + User, 936 + "bar.old is updated to baz.new = \"bar.old #1 updated\"", 937 + ), 919 938 ] 920 939 "#); 921 940 insta::assert_snapshot!(config.layers()[0].data, @r"
+40 -26
lib/src/default_index/store.rs
··· 15 15 #![allow(missing_docs)] 16 16 17 17 use std::any::Any; 18 - use std::collections::HashSet; 18 + use std::collections::HashMap; 19 19 use std::fs; 20 20 use std::io; 21 21 use std::io::Write as _; 22 22 use std::path::Path; 23 23 use std::path::PathBuf; 24 + use std::slice; 24 25 use std::sync::Arc; 25 26 26 27 use itertools::Itertools as _; ··· 49 50 use crate::object_id::ObjectId as _; 50 51 use crate::op_store::OpStoreError; 51 52 use crate::op_store::OperationId; 53 + use crate::op_walk; 52 54 use crate::operation::Operation; 53 55 use crate::store::Store; 54 56 ··· 185 187 operation: &Operation, 186 188 store: &Arc<Store>, 187 189 ) -> Result<Arc<ReadonlyIndexSegment>, DefaultIndexStoreError> { 188 - let view = operation.view()?; 190 + tracing::info!("scanning operations to index"); 189 191 let operations_dir = self.operations_dir(); 190 192 let commit_id_length = store.commit_id_length(); 191 193 let change_id_length = store.change_id_length(); 192 - let mut visited_heads: HashSet<CommitId> = 193 - view.all_referenced_commit_ids().cloned().collect(); 194 - let mut historical_heads: Vec<(CommitId, OperationId)> = visited_heads 194 + let ops_to_visit: Vec<_> = 195 + op_walk::walk_ancestors(slice::from_ref(operation)).try_collect()?; 196 + // Pick the latest existing ancestor operation as the parent segment. 197 + let parent_op = ops_to_visit 195 198 .iter() 196 - .map(|commit_id| (commit_id.clone(), operation.id().clone())) 197 - .collect(); 198 - let mut parent_op_id: Option<OperationId> = None; 199 - for op in dag_walk::dfs_ok( 200 - [Ok(operation.clone())], 201 - |op: &Operation| op.id().clone(), 202 - |op: &Operation| op.parents().collect_vec(), 203 - ) { 204 - let op = op?; 205 - // Pick the latest existing ancestor operation as the parent 206 - // segment. Perhaps, breadth-first search is more appropriate here, 207 - // but that wouldn't matter in practice as the operation log is 208 - // mostly linear. 209 - if parent_op_id.is_none() && operations_dir.join(op.id().hex()).is_file() { 210 - parent_op_id = Some(op.id().clone()); 199 + .find(|op| operations_dir.join(op.id().hex()).is_file()) 200 + .cloned(); 201 + // Remove ancestors of the latest existing operation, which should have 202 + // been indexed in the parent segment. This could be optimized for 203 + // linear history, but parent_op is often None. 204 + let ops_to_visit = if let Some(op) = &parent_op { 205 + let mut wanted_ops: HashMap<&OperationId, &Operation> = 206 + ops_to_visit.iter().map(|op| (op.id(), op)).collect(); 207 + let mut work = vec![op.id()]; 208 + while let Some(id) = work.pop() { 209 + if let Some(op) = wanted_ops.remove(id) { 210 + work.extend(op.parent_ids()); 211 + } 211 212 } 212 - // TODO: no need to walk ancestors of the parent_op_id operation 213 + ops_to_visit 214 + .iter() 215 + .filter(|op| wanted_ops.contains_key(op.id())) 216 + .cloned() 217 + .collect() 218 + } else { 219 + ops_to_visit 220 + }; 221 + tracing::info!( 222 + ops_count = ops_to_visit.len(), 223 + "collecting head commits to index" 224 + ); 225 + let mut historical_heads: HashMap<CommitId, OperationId> = HashMap::new(); 226 + for op in &ops_to_visit { 213 227 for commit_id in op.view()?.all_referenced_commit_ids() { 214 - if visited_heads.insert(commit_id.clone()) { 215 - historical_heads.push((commit_id.clone(), op.id().clone())); 228 + if !historical_heads.contains_key(commit_id) { 229 + historical_heads.insert(commit_id.clone(), op.id().clone()); 216 230 } 217 231 } 218 232 } 219 233 let maybe_parent_file; 220 234 let mut mutable_index; 221 - match parent_op_id { 235 + match &parent_op { 222 236 None => { 223 237 maybe_parent_file = None; 224 238 mutable_index = DefaultMutableIndex::full(commit_id_length, change_id_length); 225 239 } 226 - Some(parent_op_id) => { 240 + Some(op) => { 227 241 let parent_file = self.load_index_segments_at_operation( 228 - &parent_op_id, 242 + op.id(), 229 243 commit_id_length, 230 244 change_id_length, 231 245 )?;
+4 -19
lib/src/repo.rs
··· 1406 1406 /// The content of those descendants will remain untouched. 1407 1407 /// Returns the number of reparented descendants. 1408 1408 pub fn reparent_descendants(&mut self) -> BackendResult<usize> { 1409 + let roots = self.parent_mapping.keys().cloned().collect_vec(); 1409 1410 let mut num_reparented = 0; 1410 - self.reparent_descendants_with_progress(|_, _| { 1411 - num_reparented += 1; 1412 - })?; 1413 - Ok(num_reparented) 1414 - } 1415 - 1416 - /// Reparent descendants, and call the provided function for each moved 1417 - /// commit 1418 - /// 1419 - /// The function takes the old commit and the reparented commit. 1420 - pub fn reparent_descendants_with_progress( 1421 - &mut self, 1422 - mut progress: impl FnMut(Commit, Commit), 1423 - ) -> BackendResult<()> { 1424 - let roots = self.parent_mapping.keys().cloned().collect_vec(); 1425 1411 self.transform_descendants(roots, |rewriter| { 1426 1412 if rewriter.parents_changed() { 1427 - let old_commit = rewriter.old_commit().clone(); 1428 1413 let builder = rewriter.reparent(); 1429 - let reparented_commit = builder.write()?; 1430 - progress(old_commit, reparented_commit); 1414 + builder.write()?; 1415 + num_reparented += 1; 1431 1416 } 1432 1417 Ok(()) 1433 1418 })?; 1434 1419 self.parent_mapping.clear(); 1435 - Ok(()) 1420 + Ok(num_reparented) 1436 1421 } 1437 1422 1438 1423 pub fn set_wc_commit(
+11 -29
lib/src/rewrite.rs
··· 1109 1109 pub abandoned_commits: Vec<Commit>, 1110 1110 } 1111 1111 1112 - #[derive(Clone, Debug)] 1113 - pub struct SquashOptions { 1114 - pub keep_emptied: bool, 1115 - pub restore_descendants: bool, 1116 - } 1117 - 1118 1112 /// Squash `sources` into `destination` and return a [`SquashedCommit`] for the 1119 1113 /// resulting commit. Caller is responsible for setting the description and 1120 1114 /// finishing the commit. ··· 1122 1116 repo: &'repo mut MutableRepo, 1123 1117 sources: &[CommitWithSelection], 1124 1118 destination: &Commit, 1125 - SquashOptions { 1126 - keep_emptied, 1127 - restore_descendants, 1128 - }: SquashOptions, 1119 + keep_emptied: bool, 1129 1120 ) -> BackendResult<Option<SquashedCommit<'repo>>> { 1130 1121 struct SourceCommit<'a> { 1131 1122 commit: &'a CommitWithSelection, ··· 1178 1169 // rewritten sources. Otherwise it will likely already have the content 1179 1170 // changes we're moving, so applying them will have no effect and the 1180 1171 // changes will disappear. 1181 - if restore_descendants { 1182 - repo.reparent_descendants_with_progress(|old_commit, rebased_commit| { 1183 - if old_commit.id() != destination.id() { 1184 - return; 1185 - } 1186 - rewritten_destination = rebased_commit; 1187 - })?; 1188 - } else { 1189 - let options = RebaseOptions::default(); 1190 - repo.rebase_descendants_with_options(&options, |old_commit, rebased_commit| { 1191 - if old_commit.id() != destination.id() { 1192 - return; 1193 - } 1194 - rewritten_destination = match rebased_commit { 1195 - RebasedCommit::Rewritten(commit) => commit, 1196 - RebasedCommit::Abandoned { .. } => panic!("all commits should be kept"), 1197 - }; 1198 - })?; 1199 - } 1172 + let options = RebaseOptions::default(); 1173 + repo.rebase_descendants_with_options(&options, |old_commit, rebased_commit| { 1174 + if old_commit.id() != destination.id() { 1175 + return; 1176 + } 1177 + rewritten_destination = match rebased_commit { 1178 + RebasedCommit::Rewritten(commit) => commit, 1179 + RebasedCommit::Abandoned { .. } => panic!("all commits should be kept"), 1180 + }; 1181 + })?; 1200 1182 } 1201 1183 // Apply the selected changes onto the destination 1202 1184 let mut destination_tree = rewritten_destination.tree()?;