just playing with tangled
at main 472 lines 18 kB view raw
1// Copyright 2022 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use crate::common::create_commit_with_files; 16use crate::common::TestEnvironment; 17 18#[test] 19fn test_status_copies() { 20 let test_env = TestEnvironment::default(); 21 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 22 let work_dir = test_env.work_dir("repo"); 23 24 work_dir.write_file("copy-source", "copy1\ncopy2\ncopy3\n"); 25 work_dir.write_file("rename-source", "rename"); 26 work_dir.run_jj(["new"]).success(); 27 work_dir.write_file("copy-source", "copy1\ncopy2\ncopy3\nsource\n"); 28 work_dir.write_file("copy-target", "copy1\ncopy2\ncopy3\ntarget\n"); 29 work_dir.remove_file("rename-source"); 30 work_dir.write_file("rename-target", "rename"); 31 32 let output = work_dir.run_jj(["status"]); 33 insta::assert_snapshot!(output, @r" 34 Working copy changes: 35 M copy-source 36 C {copy-source => copy-target} 37 R {rename-source => rename-target} 38 Working copy (@) : rlvkpnrz c2fce842 (no description set) 39 Parent commit (@-): qpvuntsm ebf799bc (no description set) 40 [EOF] 41 "); 42} 43 44#[test] 45fn test_status_merge() { 46 let test_env = TestEnvironment::default(); 47 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 48 let work_dir = test_env.work_dir("repo"); 49 50 work_dir.write_file("file", "base"); 51 work_dir.run_jj(["new", "-m=left"]).success(); 52 work_dir 53 .run_jj(["bookmark", "create", "-r@", "left"]) 54 .success(); 55 work_dir.run_jj(["new", "@-", "-m=right"]).success(); 56 work_dir.write_file("file", "right"); 57 work_dir.run_jj(["new", "left", "@"]).success(); 58 59 // The output should mention each parent, and the diff should be empty (compared 60 // to the auto-merged parents) 61 let output = work_dir.run_jj(["status"]); 62 insta::assert_snapshot!(output, @r" 63 The working copy has no changes. 64 Working copy (@) : mzvwutvl f62dad77 (empty) (no description set) 65 Parent commit (@-): rlvkpnrz a007d87b left | (empty) left 66 Parent commit (@-): zsuskuln e6ad1952 right 67 [EOF] 68 "); 69} 70 71// See https://github.com/jj-vcs/jj/issues/2051. 72#[test] 73fn test_status_ignored_gitignore() { 74 let test_env = TestEnvironment::default(); 75 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 76 let work_dir = test_env.work_dir("repo"); 77 78 let untracked_dir = work_dir.create_dir("untracked"); 79 untracked_dir.write_file("inside_untracked", "test"); 80 untracked_dir.write_file(".gitignore", "!inside_untracked\n"); 81 work_dir.write_file(".gitignore", "untracked/\n!dummy\n"); 82 83 let output = work_dir.run_jj(["status"]); 84 insta::assert_snapshot!(output, @r" 85 Working copy changes: 86 A .gitignore 87 Working copy (@) : qpvuntsm 32bad97e (no description set) 88 Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) 89 [EOF] 90 "); 91} 92 93#[test] 94fn test_status_filtered() { 95 let test_env = TestEnvironment::default(); 96 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 97 let work_dir = test_env.work_dir("repo"); 98 99 work_dir.write_file("file_1", "file_1"); 100 work_dir.write_file("file_2", "file_2"); 101 102 // The output filtered to file_1 should not list the addition of file_2. 103 let output = work_dir.run_jj(["status", "file_1"]); 104 insta::assert_snapshot!(output, @r" 105 Working copy changes: 106 A file_1 107 Working copy (@) : qpvuntsm 2f169edb (no description set) 108 Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) 109 [EOF] 110 "); 111} 112 113// See <https://github.com/jj-vcs/jj/issues/3108> 114// See <https://github.com/jj-vcs/jj/issues/4147> 115#[test] 116fn test_status_display_relevant_working_commit_conflict_hints() { 117 let test_env = TestEnvironment::default(); 118 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 119 120 let work_dir = test_env.work_dir("repo"); 121 // PARENT: Write the initial file 122 work_dir.write_file("conflicted.txt", "initial contents"); 123 work_dir 124 .run_jj(["describe", "--message", "Initial contents"]) 125 .success(); 126 127 // CHILD1: New commit on top of <PARENT> 128 work_dir 129 .run_jj(["new", "--message", "First part of conflicting change"]) 130 .success(); 131 work_dir.write_file("conflicted.txt", "Child 1"); 132 133 // CHILD2: New commit also on top of <PARENT> 134 work_dir 135 .run_jj([ 136 "new", 137 "--message", 138 "Second part of conflicting change", 139 "@-", 140 ]) 141 .success(); 142 work_dir.write_file("conflicted.txt", "Child 2"); 143 144 // CONFLICT: New commit that is conflicted by merging <CHILD1> and <CHILD2> 145 work_dir 146 .run_jj(["new", "--message", "boom", "all:(@-)+"]) 147 .success(); 148 // Adding more descendants to ensure we correctly find the root ancestors with 149 // conflicts, not just the parents. 150 work_dir.run_jj(["new", "--message", "boom-cont"]).success(); 151 work_dir 152 .run_jj(["new", "--message", "boom-cont-2"]) 153 .success(); 154 155 let output = work_dir.run_jj(["log", "-r", "::"]); 156 157 insta::assert_snapshot!(output, @r" 158 @ yqosqzyt test.user@example.com 2001-02-03 08:05:13 7e0bc4cf conflict 159 │ (empty) boom-cont-2 160 × royxmykx test.user@example.com 2001-02-03 08:05:12 681c71af conflict 161 │ (empty) boom-cont 162 × mzvwutvl test.user@example.com 2001-02-03 08:05:11 30558616 conflict 163 ├─╮ (empty) boom 164 │ ○ kkmpptxz test.user@example.com 2001-02-03 08:05:10 bb11a679 165 │ │ First part of conflicting change 166 ○ │ zsuskuln test.user@example.com 2001-02-03 08:05:11 b6dfc209 167 ├─╯ Second part of conflicting change 168 ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 fe876a9c 169 │ Initial contents 170 ◆ zzzzzzzz root() 00000000 171 [EOF] 172 "); 173 174 let output = work_dir.run_jj(["status"]); 175 insta::assert_snapshot!(output, @r###" 176 The working copy has no changes. 177 Working copy (@) : yqosqzyt 7e0bc4cf (conflict) (empty) boom-cont-2 178 Parent commit (@-): royxmykx 681c71af (conflict) (empty) boom-cont 179 Warning: There are unresolved conflicts at these paths: 180 conflicted.txt 2-sided conflict 181 Hint: To resolve the conflicts, start by creating a commit on top of 182 the first conflicted commit: 183 jj new mzvwutvl 184 Then use `jj resolve`, or edit the conflict markers in the file directly. 185 Once the conflicts are resolved, you can inspect the result with `jj diff`. 186 Then run `jj squash` to move the resolution into the conflicted commit. 187 [EOF] 188 "###); 189 190 let output = work_dir.run_jj(["status", "--color=always"]); 191 insta::assert_snapshot!(output, @r###" 192 The working copy has no changes. 193 Working copy (@) : yqosqzyt 7e0bc4cf (conflict) (empty) boom-cont-2 194 Parent commit (@-): royxmykx 681c71af (conflict) (empty) boom-cont 195 Warning: There are unresolved conflicts at these paths: 196 conflicted.txt 2-sided conflict 197 Hint: To resolve the conflicts, start by creating a commit on top of 198 the first conflicted commit: 199  jj new mzvwutvl 200 Then use `jj resolve`, or edit the conflict markers in the file directly. 201 Once the conflicts are resolved, you can inspect the result with `jj diff`. 202 Then run `jj squash` to move the resolution into the conflicted commit. 203 [EOF] 204 "###); 205 206 let output = work_dir.run_jj(["status", "--config=hints.resolving-conflicts=false"]); 207 insta::assert_snapshot!(output, @r" 208 The working copy has no changes. 209 Working copy (@) : yqosqzyt 7e0bc4cf (conflict) (empty) boom-cont-2 210 Parent commit (@-): royxmykx 681c71af (conflict) (empty) boom-cont 211 Warning: There are unresolved conflicts at these paths: 212 conflicted.txt 2-sided conflict 213 [EOF] 214 "); 215 216 // Resolve conflict 217 work_dir.run_jj(["new", "--message", "fixed 1"]).success(); 218 work_dir.write_file("conflicted.txt", "first commit to fix conflict"); 219 220 // Add one more commit atop the commit that resolves the conflict. 221 work_dir.run_jj(["new", "--message", "fixed 2"]).success(); 222 work_dir.write_file("conflicted.txt", "edit not conflict"); 223 224 // wc is now conflict free, parent is also conflict free 225 let output = work_dir.run_jj(["log", "-r", "::"]); 226 227 insta::assert_snapshot!(output, @r" 228 @ wqnwkozp test.user@example.com 2001-02-03 08:05:20 cc7d68f7 229 │ fixed 2 230 ○ kmkuslsw test.user@example.com 2001-02-03 08:05:19 812e2163 231 │ fixed 1 232 × yqosqzyt test.user@example.com 2001-02-03 08:05:13 7e0bc4cf conflict 233 │ (empty) boom-cont-2 234 × royxmykx test.user@example.com 2001-02-03 08:05:12 681c71af conflict 235 │ (empty) boom-cont 236 × mzvwutvl test.user@example.com 2001-02-03 08:05:11 30558616 conflict 237 ├─╮ (empty) boom 238 │ ○ kkmpptxz test.user@example.com 2001-02-03 08:05:10 bb11a679 239 │ │ First part of conflicting change 240 ○ │ zsuskuln test.user@example.com 2001-02-03 08:05:11 b6dfc209 241 ├─╯ Second part of conflicting change 242 ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 fe876a9c 243 │ Initial contents 244 ◆ zzzzzzzz root() 00000000 245 [EOF] 246 "); 247 248 let output = work_dir.run_jj(["status"]); 249 250 insta::assert_snapshot!(output, @r" 251 Working copy changes: 252 M conflicted.txt 253 Working copy (@) : wqnwkozp cc7d68f7 fixed 2 254 Parent commit (@-): kmkuslsw 812e2163 fixed 1 255 [EOF] 256 "); 257 258 // Step back one. 259 // wc is still conflict free, parent has a conflict. 260 work_dir.run_jj(["edit", "@-"]).success(); 261 let output = work_dir.run_jj(["log", "-r", "::"]); 262 263 insta::assert_snapshot!(output, @r" 264 ○ wqnwkozp test.user@example.com 2001-02-03 08:05:20 cc7d68f7 265 │ fixed 2 266 @ kmkuslsw test.user@example.com 2001-02-03 08:05:19 812e2163 267 │ fixed 1 268 × yqosqzyt test.user@example.com 2001-02-03 08:05:13 7e0bc4cf conflict 269 │ (empty) boom-cont-2 270 × royxmykx test.user@example.com 2001-02-03 08:05:12 681c71af conflict 271 │ (empty) boom-cont 272 × mzvwutvl test.user@example.com 2001-02-03 08:05:11 30558616 conflict 273 ├─╮ (empty) boom 274 │ ○ kkmpptxz test.user@example.com 2001-02-03 08:05:10 bb11a679 275 │ │ First part of conflicting change 276 ○ │ zsuskuln test.user@example.com 2001-02-03 08:05:11 b6dfc209 277 ├─╯ Second part of conflicting change 278 ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 fe876a9c 279 │ Initial contents 280 ◆ zzzzzzzz root() 00000000 281 [EOF] 282 "); 283 284 let output = work_dir.run_jj(["status"]); 285 286 insta::assert_snapshot!(output, @r" 287 Working copy changes: 288 M conflicted.txt 289 Working copy (@) : kmkuslsw 812e2163 fixed 1 290 Parent commit (@-): yqosqzyt 7e0bc4cf (conflict) (empty) boom-cont-2 291 Hint: Conflict in parent commit has been resolved in working copy 292 [EOF] 293 "); 294 295 // Step back to all the way to `root()+` so that wc has no conflict, even though 296 // there is a conflict later in the tree. So that we can confirm 297 // our hinting logic doesn't get confused. 298 work_dir.run_jj(["edit", "root()+"]).success(); 299 let output = work_dir.run_jj(["log", "-r", "::"]); 300 301 insta::assert_snapshot!(output, @r" 302 ○ wqnwkozp test.user@example.com 2001-02-03 08:05:20 cc7d68f7 303 │ fixed 2 304 ○ kmkuslsw test.user@example.com 2001-02-03 08:05:19 812e2163 305 │ fixed 1 306 × yqosqzyt test.user@example.com 2001-02-03 08:05:13 7e0bc4cf conflict 307 │ (empty) boom-cont-2 308 × royxmykx test.user@example.com 2001-02-03 08:05:12 681c71af conflict 309 │ (empty) boom-cont 310 × mzvwutvl test.user@example.com 2001-02-03 08:05:11 30558616 conflict 311 ├─╮ (empty) boom 312 │ ○ kkmpptxz test.user@example.com 2001-02-03 08:05:10 bb11a679 313 │ │ First part of conflicting change 314 ○ │ zsuskuln test.user@example.com 2001-02-03 08:05:11 b6dfc209 315 ├─╯ Second part of conflicting change 316 @ qpvuntsm test.user@example.com 2001-02-03 08:05:08 fe876a9c 317 │ Initial contents 318 ◆ zzzzzzzz root() 00000000 319 [EOF] 320 "); 321 322 let output = work_dir.run_jj(["status"]); 323 324 insta::assert_snapshot!(output, @r" 325 Working copy changes: 326 A conflicted.txt 327 Working copy (@) : qpvuntsm fe876a9c Initial contents 328 Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) 329 [EOF] 330 "); 331} 332 333#[test] 334fn test_status_simplify_conflict_sides() { 335 let test_env = TestEnvironment::default(); 336 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 337 let work_dir = test_env.work_dir("repo"); 338 339 // Creates a 4-sided conflict, with fileA and fileB having different conflicts: 340 // fileA: A - B + C - B + B - B + B 341 // fileB: A - A + A - A + B - C + D 342 create_commit_with_files( 343 &work_dir, 344 "base", 345 &[], 346 &[("fileA", "base\n"), ("fileB", "base\n")], 347 ); 348 create_commit_with_files(&work_dir, "a1", &["base"], &[("fileA", "1\n")]); 349 create_commit_with_files(&work_dir, "a2", &["base"], &[("fileA", "2\n")]); 350 create_commit_with_files(&work_dir, "b1", &["base"], &[("fileB", "1\n")]); 351 create_commit_with_files(&work_dir, "b2", &["base"], &[("fileB", "2\n")]); 352 create_commit_with_files(&work_dir, "conflictA", &["a1", "a2"], &[]); 353 create_commit_with_files(&work_dir, "conflictB", &["b1", "b2"], &[]); 354 create_commit_with_files(&work_dir, "conflict", &["conflictA", "conflictB"], &[]); 355 356 insta::assert_snapshot!(work_dir.run_jj(["status"]), 357 @r###" 358 The working copy has no changes. 359 Working copy (@) : nkmrtpmo a5a545ce conflict | (conflict) (empty) conflict 360 Parent commit (@-): kmkuslsw ccb05364 conflictA | (conflict) (empty) conflictA 361 Parent commit (@-): lylxulpl d9bc60cb conflictB | (conflict) (empty) conflictB 362 Warning: There are unresolved conflicts at these paths: 363 fileA 2-sided conflict 364 fileB 2-sided conflict 365 Hint: To resolve the conflicts, start by creating a commit on top of 366 one of the first conflicted commits: 367 jj new lylxulpl 368 jj new kmkuslsw 369 Then use `jj resolve`, or edit the conflict markers in the file directly. 370 Once the conflicts are resolved, you can inspect the result with `jj diff`. 371 Then run `jj squash` to move the resolution into the conflicted commit. 372 [EOF] 373 "###); 374} 375 376#[test] 377fn test_status_untracked_files() { 378 let test_env = TestEnvironment::default(); 379 test_env.add_config(r#"snapshot.auto-track = "none()""#); 380 381 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 382 let work_dir = test_env.work_dir("repo"); 383 384 work_dir.write_file("always-untracked-file", "..."); 385 work_dir.write_file("initially-untracked-file", "..."); 386 let sub_dir = work_dir.create_dir("sub"); 387 sub_dir.write_file("always-untracked", "..."); 388 sub_dir.write_file("initially-untracked", "..."); 389 390 let output = work_dir.run_jj(["status"]); 391 insta::assert_snapshot!(output.normalize_backslash(), @r" 392 Untracked paths: 393 ? always-untracked-file 394 ? initially-untracked-file 395 ? sub/always-untracked 396 ? sub/initially-untracked 397 Working copy (@) : qpvuntsm e8849ae1 (empty) (no description set) 398 Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) 399 [EOF] 400 "); 401 402 work_dir 403 .run_jj([ 404 "file", 405 "track", 406 "initially-untracked-file", 407 "sub/initially-untracked", 408 ]) 409 .success(); 410 411 let output = work_dir.run_jj(["status"]); 412 insta::assert_snapshot!(output.normalize_backslash(), @r" 413 Working copy changes: 414 A initially-untracked-file 415 A sub/initially-untracked 416 Untracked paths: 417 ? always-untracked-file 418 ? sub/always-untracked 419 Working copy (@) : qpvuntsm b8c1286d (no description set) 420 Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) 421 [EOF] 422 "); 423 424 work_dir.run_jj(["new"]).success(); 425 426 let output = work_dir.run_jj(["status"]); 427 insta::assert_snapshot!(output.normalize_backslash(), @r" 428 Untracked paths: 429 ? always-untracked-file 430 ? sub/always-untracked 431 Working copy (@) : mzvwutvl daa133b8 (empty) (no description set) 432 Parent commit (@-): qpvuntsm b8c1286d (no description set) 433 [EOF] 434 "); 435 436 work_dir 437 .run_jj([ 438 "file", 439 "untrack", 440 "initially-untracked-file", 441 "sub/initially-untracked", 442 ]) 443 .success(); 444 let output = work_dir.run_jj(["status"]); 445 insta::assert_snapshot!(output.normalize_backslash(), @r" 446 Working copy changes: 447 D initially-untracked-file 448 D sub/initially-untracked 449 Untracked paths: 450 ? always-untracked-file 451 ? initially-untracked-file 452 ? sub/always-untracked 453 ? sub/initially-untracked 454 Working copy (@) : mzvwutvl 240f261a (no description set) 455 Parent commit (@-): qpvuntsm b8c1286d (no description set) 456 [EOF] 457 "); 458 459 work_dir.run_jj(["new"]).success(); 460 461 let output = work_dir.run_jj(["status"]); 462 insta::assert_snapshot!(output.normalize_backslash(), @r" 463 Untracked paths: 464 ? always-untracked-file 465 ? initially-untracked-file 466 ? sub/always-untracked 467 ? sub/initially-untracked 468 Working copy (@) : yostqsxw 50beac0d (empty) (no description set) 469 Parent commit (@-): mzvwutvl 240f261a (no description set) 470 [EOF] 471 "); 472}