fork of go-git with some jj specific features
at v5.4.0 55 kB view raw
1package git 2 3import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "regexp" 12 "runtime" 13 "testing" 14 "time" 15 16 fixtures "github.com/go-git/go-git-fixtures/v4" 17 "github.com/go-git/go-git/v5/config" 18 "github.com/go-git/go-git/v5/plumbing" 19 "github.com/go-git/go-git/v5/plumbing/filemode" 20 "github.com/go-git/go-git/v5/plumbing/format/gitignore" 21 "github.com/go-git/go-git/v5/plumbing/format/index" 22 "github.com/go-git/go-git/v5/plumbing/object" 23 "github.com/go-git/go-git/v5/storage/memory" 24 25 "github.com/go-git/go-billy/v5/memfs" 26 "github.com/go-git/go-billy/v5/osfs" 27 "github.com/go-git/go-billy/v5/util" 28 "golang.org/x/text/unicode/norm" 29 . "gopkg.in/check.v1" 30) 31 32type WorktreeSuite struct { 33 BaseSuite 34} 35 36var _ = Suite(&WorktreeSuite{}) 37 38func (s *WorktreeSuite) SetUpTest(c *C) { 39 f := fixtures.Basic().One() 40 s.Repository = s.NewRepositoryWithEmptyWorktree(f) 41} 42 43func (s *WorktreeSuite) TestPullCheckout(c *C) { 44 fs := memfs.New() 45 r, _ := Init(memory.NewStorage(), fs) 46 r.CreateRemote(&config.RemoteConfig{ 47 Name: DefaultRemoteName, 48 URLs: []string{s.GetBasicLocalRepositoryURL()}, 49 }) 50 51 w, err := r.Worktree() 52 c.Assert(err, IsNil) 53 54 err = w.Pull(&PullOptions{}) 55 c.Assert(err, IsNil) 56 57 fi, err := fs.ReadDir("") 58 c.Assert(err, IsNil) 59 c.Assert(fi, HasLen, 8) 60} 61 62func (s *WorktreeSuite) TestPullFastForward(c *C) { 63 url, clean := s.TemporalDir() 64 defer clean() 65 66 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 67 68 server, err := PlainClone(url, false, &CloneOptions{ 69 URL: path, 70 }) 71 c.Assert(err, IsNil) 72 73 dir, clean := s.TemporalDir() 74 defer clean() 75 76 r, err := PlainClone(dir, false, &CloneOptions{ 77 URL: url, 78 }) 79 c.Assert(err, IsNil) 80 81 w, err := server.Worktree() 82 c.Assert(err, IsNil) 83 err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) 84 c.Assert(err, IsNil) 85 hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()}) 86 c.Assert(err, IsNil) 87 88 w, err = r.Worktree() 89 c.Assert(err, IsNil) 90 91 err = w.Pull(&PullOptions{}) 92 c.Assert(err, IsNil) 93 94 head, err := r.Head() 95 c.Assert(err, IsNil) 96 c.Assert(head.Hash(), Equals, hash) 97} 98 99func (s *WorktreeSuite) TestPullNonFastForward(c *C) { 100 url, clean := s.TemporalDir() 101 defer clean() 102 103 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 104 105 server, err := PlainClone(url, false, &CloneOptions{ 106 URL: path, 107 }) 108 c.Assert(err, IsNil) 109 110 dir, clean := s.TemporalDir() 111 defer clean() 112 113 r, err := PlainClone(dir, false, &CloneOptions{ 114 URL: url, 115 }) 116 c.Assert(err, IsNil) 117 118 w, err := server.Worktree() 119 c.Assert(err, IsNil) 120 err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) 121 c.Assert(err, IsNil) 122 _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) 123 c.Assert(err, IsNil) 124 125 w, err = r.Worktree() 126 c.Assert(err, IsNil) 127 err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755) 128 c.Assert(err, IsNil) 129 _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()}) 130 c.Assert(err, IsNil) 131 132 err = w.Pull(&PullOptions{}) 133 c.Assert(err, Equals, ErrNonFastForwardUpdate) 134} 135 136func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) { 137 r, _ := Init(memory.NewStorage(), memfs.New()) 138 r.CreateRemote(&config.RemoteConfig{ 139 Name: DefaultRemoteName, 140 URLs: []string{s.GetBasicLocalRepositoryURL()}, 141 }) 142 143 err := r.Fetch(&FetchOptions{}) 144 c.Assert(err, IsNil) 145 146 _, err = r.Reference("refs/heads/master", false) 147 c.Assert(err, NotNil) 148 149 w, err := r.Worktree() 150 c.Assert(err, IsNil) 151 152 err = w.Pull(&PullOptions{}) 153 c.Assert(err, IsNil) 154 155 head, err := r.Reference(plumbing.HEAD, true) 156 c.Assert(err, IsNil) 157 c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 158 159 branch, err := r.Reference("refs/heads/master", false) 160 c.Assert(err, IsNil) 161 c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 162 163 err = w.Pull(&PullOptions{}) 164 c.Assert(err, Equals, NoErrAlreadyUpToDate) 165} 166 167func (s *WorktreeSuite) TestPullInSingleBranch(c *C) { 168 r, _ := Init(memory.NewStorage(), memfs.New()) 169 err := r.clone(context.Background(), &CloneOptions{ 170 URL: s.GetBasicLocalRepositoryURL(), 171 SingleBranch: true, 172 }) 173 174 c.Assert(err, IsNil) 175 176 w, err := r.Worktree() 177 c.Assert(err, IsNil) 178 179 err = w.Pull(&PullOptions{}) 180 c.Assert(err, Equals, NoErrAlreadyUpToDate) 181 182 branch, err := r.Reference("refs/heads/master", false) 183 c.Assert(err, IsNil) 184 c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 185 186 branch, err = r.Reference("refs/remotes/foo/branch", false) 187 c.Assert(err, NotNil) 188 189 storage := r.Storer.(*memory.Storage) 190 c.Assert(storage.Objects, HasLen, 28) 191} 192 193func (s *WorktreeSuite) TestPullProgress(c *C) { 194 r, _ := Init(memory.NewStorage(), memfs.New()) 195 196 r.CreateRemote(&config.RemoteConfig{ 197 Name: DefaultRemoteName, 198 URLs: []string{s.GetBasicLocalRepositoryURL()}, 199 }) 200 201 w, err := r.Worktree() 202 c.Assert(err, IsNil) 203 204 buf := bytes.NewBuffer(nil) 205 err = w.Pull(&PullOptions{ 206 Progress: buf, 207 }) 208 209 c.Assert(err, IsNil) 210 c.Assert(buf.Len(), Not(Equals), 0) 211} 212 213func (s *WorktreeSuite) TestPullProgressWithRecursion(c *C) { 214 if testing.Short() { 215 c.Skip("skipping test in short mode.") 216 } 217 218 path := fixtures.ByTag("submodule").One().Worktree().Root() 219 220 dir, clean := s.TemporalDir() 221 defer clean() 222 223 r, _ := PlainInit(dir, false) 224 r.CreateRemote(&config.RemoteConfig{ 225 Name: DefaultRemoteName, 226 URLs: []string{path}, 227 }) 228 229 w, err := r.Worktree() 230 c.Assert(err, IsNil) 231 232 err = w.Pull(&PullOptions{ 233 RecurseSubmodules: DefaultSubmoduleRecursionDepth, 234 }) 235 c.Assert(err, IsNil) 236 237 cfg, err := r.Config() 238 c.Assert(err, IsNil) 239 c.Assert(cfg.Submodules, HasLen, 2) 240} 241 242func (s *RepositorySuite) TestPullAdd(c *C) { 243 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 244 245 r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ 246 URL: filepath.Join(path, ".git"), 247 }) 248 249 c.Assert(err, IsNil) 250 251 storage := r.Storer.(*memory.Storage) 252 c.Assert(storage.Objects, HasLen, 28) 253 254 branch, err := r.Reference("refs/heads/master", false) 255 c.Assert(err, IsNil) 256 c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 257 258 ExecuteOnPath(c, path, 259 "touch foo", 260 "git add foo", 261 "git commit -m foo foo", 262 ) 263 264 w, err := r.Worktree() 265 c.Assert(err, IsNil) 266 267 err = w.Pull(&PullOptions{RemoteName: "origin"}) 268 c.Assert(err, IsNil) 269 270 // the commit command has introduced a new commit, tree and blob 271 c.Assert(storage.Objects, HasLen, 31) 272 273 branch, err = r.Reference("refs/heads/master", false) 274 c.Assert(err, IsNil) 275 c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 276} 277 278func (s *WorktreeSuite) TestPullAlreadyUptodate(c *C) { 279 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 280 281 r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ 282 URL: filepath.Join(path, ".git"), 283 }) 284 285 c.Assert(err, IsNil) 286 287 w, err := r.Worktree() 288 c.Assert(err, IsNil) 289 err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755) 290 c.Assert(err, IsNil) 291 _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()}) 292 c.Assert(err, IsNil) 293 294 err = w.Pull(&PullOptions{}) 295 c.Assert(err, Equals, NoErrAlreadyUpToDate) 296} 297 298func (s *WorktreeSuite) TestCheckout(c *C) { 299 fs := memfs.New() 300 w := &Worktree{ 301 r: s.Repository, 302 Filesystem: fs, 303 } 304 305 err := w.Checkout(&CheckoutOptions{ 306 Force: true, 307 }) 308 c.Assert(err, IsNil) 309 310 entries, err := fs.ReadDir("/") 311 c.Assert(err, IsNil) 312 313 c.Assert(entries, HasLen, 8) 314 ch, err := fs.Open("CHANGELOG") 315 c.Assert(err, IsNil) 316 317 content, err := ioutil.ReadAll(ch) 318 c.Assert(err, IsNil) 319 c.Assert(string(content), Equals, "Initial changelog\n") 320 321 idx, err := s.Repository.Storer.Index() 322 c.Assert(err, IsNil) 323 c.Assert(idx.Entries, HasLen, 9) 324} 325 326func (s *WorktreeSuite) TestCheckoutForce(c *C) { 327 w := &Worktree{ 328 r: s.Repository, 329 Filesystem: memfs.New(), 330 } 331 332 err := w.Checkout(&CheckoutOptions{}) 333 c.Assert(err, IsNil) 334 335 w.Filesystem = memfs.New() 336 337 err = w.Checkout(&CheckoutOptions{ 338 Force: true, 339 }) 340 c.Assert(err, IsNil) 341 342 entries, err := w.Filesystem.ReadDir("/") 343 c.Assert(err, IsNil) 344 c.Assert(entries, HasLen, 8) 345} 346 347func (s *WorktreeSuite) TestCheckoutKeep(c *C) { 348 w := &Worktree{ 349 r: s.Repository, 350 Filesystem: memfs.New(), 351 } 352 353 err := w.Checkout(&CheckoutOptions{ 354 Force: true, 355 }) 356 c.Assert(err, IsNil) 357 358 // Create a new branch and create a new file. 359 err = w.Checkout(&CheckoutOptions{ 360 Branch: plumbing.NewBranchReferenceName("new-branch"), 361 Create: true, 362 }) 363 c.Assert(err, IsNil) 364 365 w.Filesystem = memfs.New() 366 f, err := w.Filesystem.Create("new-file.txt") 367 c.Assert(err, IsNil) 368 _, err = f.Write([]byte("DUMMY")) 369 c.Assert(err, IsNil) 370 c.Assert(f.Close(), IsNil) 371 372 // Add the file to staging. 373 _, err = w.Add("new-file.txt") 374 c.Assert(err, IsNil) 375 376 // Switch branch to master, and verify that the new file was kept in staging. 377 err = w.Checkout(&CheckoutOptions{ 378 Keep: true, 379 }) 380 c.Assert(err, IsNil) 381 382 fi, err := w.Filesystem.Stat("new-file.txt") 383 c.Assert(err, IsNil) 384 c.Assert(fi.Size(), Equals, int64(5)) 385} 386 387func (s *WorktreeSuite) TestCheckoutSymlink(c *C) { 388 if runtime.GOOS == "windows" { 389 c.Skip("git doesn't support symlinks by default in windows") 390 } 391 392 dir, clean := s.TemporalDir() 393 defer clean() 394 395 r, err := PlainInit(dir, false) 396 c.Assert(err, IsNil) 397 398 w, err := r.Worktree() 399 c.Assert(err, IsNil) 400 401 w.Filesystem.Symlink("not-exists", "bar") 402 w.Add("bar") 403 w.Commit("foo", &CommitOptions{Author: defaultSignature()}) 404 405 r.Storer.SetIndex(&index.Index{Version: 2}) 406 w.Filesystem = osfs.New(filepath.Join(dir, "worktree-empty")) 407 408 err = w.Checkout(&CheckoutOptions{}) 409 c.Assert(err, IsNil) 410 411 status, err := w.Status() 412 c.Assert(err, IsNil) 413 c.Assert(status.IsClean(), Equals, true) 414 415 target, err := w.Filesystem.Readlink("bar") 416 c.Assert(target, Equals, "not-exists") 417 c.Assert(err, IsNil) 418} 419 420func (s *WorktreeSuite) TestFilenameNormalization(c *C) { 421 if runtime.GOOS == "windows" { 422 c.Skip("windows paths may contain non utf-8 sequences") 423 } 424 425 url, clean := s.TemporalDir() 426 defer clean() 427 428 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 429 430 server, err := PlainClone(url, false, &CloneOptions{ 431 URL: path, 432 }) 433 c.Assert(err, IsNil) 434 435 filename := "페" 436 437 w, err := server.Worktree() 438 c.Assert(err, IsNil) 439 440 writeFile := func(path string) { 441 err := util.WriteFile(w.Filesystem, path, []byte("foo"), 0755) 442 c.Assert(err, IsNil) 443 } 444 445 writeFile(filename) 446 origHash, err := w.Add(filename) 447 c.Assert(err, IsNil) 448 _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) 449 c.Assert(err, IsNil) 450 451 r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ 452 URL: url, 453 }) 454 c.Assert(err, IsNil) 455 456 w, err = r.Worktree() 457 c.Assert(err, IsNil) 458 459 status, err := w.Status() 460 c.Assert(err, IsNil) 461 c.Assert(status.IsClean(), Equals, true) 462 463 err = w.Filesystem.Remove(filename) 464 c.Assert(err, IsNil) 465 466 modFilename := norm.NFKD.String(filename) 467 writeFile(modFilename) 468 469 _, err = w.Add(filename) 470 c.Assert(err, IsNil) 471 modHash, err := w.Add(modFilename) 472 c.Assert(err, IsNil) 473 // At this point we've got two files with the same content. 474 // Hence their hashes must be the same. 475 c.Assert(origHash == modHash, Equals, true) 476 477 status, err = w.Status() 478 c.Assert(err, IsNil) 479 // However, their names are different and the work tree is still dirty. 480 c.Assert(status.IsClean(), Equals, false) 481 482 // Revert back the deletion of the first file. 483 writeFile(filename) 484 _, err = w.Add(filename) 485 c.Assert(err, IsNil) 486 487 status, err = w.Status() 488 c.Assert(err, IsNil) 489 // Still dirty - the second file is added. 490 c.Assert(status.IsClean(), Equals, false) 491 492 _, err = w.Remove(modFilename) 493 c.Assert(err, IsNil) 494 495 status, err = w.Status() 496 c.Assert(err, IsNil) 497 c.Assert(status.IsClean(), Equals, true) 498} 499 500func (s *WorktreeSuite) TestCheckoutSubmodule(c *C) { 501 url := "https://github.com/git-fixtures/submodule.git" 502 r := s.NewRepositoryWithEmptyWorktree(fixtures.ByURL(url).One()) 503 504 w, err := r.Worktree() 505 c.Assert(err, IsNil) 506 507 err = w.Checkout(&CheckoutOptions{}) 508 c.Assert(err, IsNil) 509 510 status, err := w.Status() 511 c.Assert(err, IsNil) 512 c.Assert(status.IsClean(), Equals, true) 513} 514 515func (s *WorktreeSuite) TestCheckoutSubmoduleInitialized(c *C) { 516 url := "https://github.com/git-fixtures/submodule.git" 517 r := s.NewRepository(fixtures.ByURL(url).One()) 518 519 w, err := r.Worktree() 520 c.Assert(err, IsNil) 521 522 sub, err := w.Submodules() 523 c.Assert(err, IsNil) 524 525 err = sub.Update(&SubmoduleUpdateOptions{Init: true}) 526 c.Assert(err, IsNil) 527 528 status, err := w.Status() 529 c.Assert(err, IsNil) 530 c.Assert(status.IsClean(), Equals, true) 531} 532 533func (s *WorktreeSuite) TestCheckoutRelativePathSubmoduleInitialized(c *C) { 534 url := "https://github.com/git-fixtures/submodule.git" 535 r := s.NewRepository(fixtures.ByURL(url).One()) 536 537 // modify the .gitmodules from original one 538 file, err := r.wt.OpenFile(".gitmodules", os.O_WRONLY|os.O_TRUNC, 0666) 539 c.Assert(err, IsNil) 540 541 n, err := io.WriteString(file, `[submodule "basic"] 542 path = basic 543 url = ../basic.git 544[submodule "itself"] 545 path = itself 546 url = ../submodule.git`) 547 c.Assert(err, IsNil) 548 c.Assert(n, Not(Equals), 0) 549 550 w, err := r.Worktree() 551 c.Assert(err, IsNil) 552 553 w.Add(".gitmodules") 554 w.Commit("test", &CommitOptions{}) 555 556 // test submodule path 557 modules, err := w.readGitmodulesFile() 558 559 c.Assert(modules.Submodules["basic"].URL, Equals, "../basic.git") 560 c.Assert(modules.Submodules["itself"].URL, Equals, "../submodule.git") 561 562 basicSubmodule, err := w.Submodule("basic") 563 c.Assert(err, IsNil) 564 basicRepo, err := basicSubmodule.Repository() 565 c.Assert(err, IsNil) 566 basicRemotes, err := basicRepo.Remotes() 567 c.Assert(err, IsNil) 568 c.Assert(basicRemotes[0].Config().URLs[0], Equals, "https://github.com/git-fixtures/basic.git") 569 570 itselfSubmodule, err := w.Submodule("itself") 571 c.Assert(err, IsNil) 572 itselfRepo, err := itselfSubmodule.Repository() 573 c.Assert(err, IsNil) 574 itselfRemotes, err := itselfRepo.Remotes() 575 c.Assert(err, IsNil) 576 c.Assert(itselfRemotes[0].Config().URLs[0], Equals, "https://github.com/git-fixtures/submodule.git") 577 578 sub, err := w.Submodules() 579 c.Assert(err, IsNil) 580 581 err = sub.Update(&SubmoduleUpdateOptions{Init: true, RecurseSubmodules: DefaultSubmoduleRecursionDepth}) 582 c.Assert(err, IsNil) 583 584 status, err := w.Status() 585 c.Assert(err, IsNil) 586 c.Assert(status.IsClean(), Equals, true) 587} 588 589func (s *WorktreeSuite) TestCheckoutIndexMem(c *C) { 590 fs := memfs.New() 591 w := &Worktree{ 592 r: s.Repository, 593 Filesystem: fs, 594 } 595 596 err := w.Checkout(&CheckoutOptions{}) 597 c.Assert(err, IsNil) 598 599 idx, err := s.Repository.Storer.Index() 600 c.Assert(err, IsNil) 601 c.Assert(idx.Entries, HasLen, 9) 602 c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") 603 c.Assert(idx.Entries[0].Name, Equals, ".gitignore") 604 c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) 605 c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) 606 c.Assert(idx.Entries[0].Size, Equals, uint32(189)) 607 608 // ctime, dev, inode, uid and gid are not supported on memfs fs 609 c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, true) 610 c.Assert(idx.Entries[0].Dev, Equals, uint32(0)) 611 c.Assert(idx.Entries[0].Inode, Equals, uint32(0)) 612 c.Assert(idx.Entries[0].UID, Equals, uint32(0)) 613 c.Assert(idx.Entries[0].GID, Equals, uint32(0)) 614} 615 616func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) { 617 fs, clean := s.TemporalFilesystem() 618 defer clean() 619 620 w := &Worktree{ 621 r: s.Repository, 622 Filesystem: fs, 623 } 624 625 err := w.Checkout(&CheckoutOptions{}) 626 c.Assert(err, IsNil) 627 628 idx, err := s.Repository.Storer.Index() 629 c.Assert(err, IsNil) 630 c.Assert(idx.Entries, HasLen, 9) 631 c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") 632 c.Assert(idx.Entries[0].Name, Equals, ".gitignore") 633 c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) 634 c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) 635 c.Assert(idx.Entries[0].Size, Equals, uint32(189)) 636 637 c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, false) 638 if runtime.GOOS != "windows" { 639 c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0)) 640 c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0)) 641 c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0)) 642 c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0)) 643 } 644} 645 646func (s *WorktreeSuite) TestCheckoutBranch(c *C) { 647 w := &Worktree{ 648 r: s.Repository, 649 Filesystem: memfs.New(), 650 } 651 652 err := w.Checkout(&CheckoutOptions{ 653 Branch: "refs/heads/branch", 654 }) 655 c.Assert(err, IsNil) 656 657 head, err := w.r.Head() 658 c.Assert(err, IsNil) 659 c.Assert(head.Name().String(), Equals, "refs/heads/branch") 660 661 status, err := w.Status() 662 c.Assert(err, IsNil) 663 c.Assert(status.IsClean(), Equals, true) 664} 665 666func (s *WorktreeSuite) TestCheckoutCreateWithHash(c *C) { 667 w := &Worktree{ 668 r: s.Repository, 669 Filesystem: memfs.New(), 670 } 671 672 err := w.Checkout(&CheckoutOptions{ 673 Create: true, 674 Branch: "refs/heads/foo", 675 Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 676 }) 677 c.Assert(err, IsNil) 678 679 head, err := w.r.Head() 680 c.Assert(err, IsNil) 681 c.Assert(head.Name().String(), Equals, "refs/heads/foo") 682 c.Assert(head.Hash(), Equals, plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")) 683 684 status, err := w.Status() 685 c.Assert(err, IsNil) 686 c.Assert(status.IsClean(), Equals, true) 687} 688 689func (s *WorktreeSuite) TestCheckoutCreate(c *C) { 690 w := &Worktree{ 691 r: s.Repository, 692 Filesystem: memfs.New(), 693 } 694 695 err := w.Checkout(&CheckoutOptions{ 696 Create: true, 697 Branch: "refs/heads/foo", 698 }) 699 c.Assert(err, IsNil) 700 701 head, err := w.r.Head() 702 c.Assert(err, IsNil) 703 c.Assert(head.Name().String(), Equals, "refs/heads/foo") 704 c.Assert(head.Hash(), Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")) 705 706 status, err := w.Status() 707 c.Assert(err, IsNil) 708 c.Assert(status.IsClean(), Equals, true) 709} 710 711func (s *WorktreeSuite) TestCheckoutBranchAndHash(c *C) { 712 w := &Worktree{ 713 r: s.Repository, 714 Filesystem: memfs.New(), 715 } 716 717 err := w.Checkout(&CheckoutOptions{ 718 Branch: "refs/heads/foo", 719 Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 720 }) 721 722 c.Assert(err, Equals, ErrBranchHashExclusive) 723} 724 725func (s *WorktreeSuite) TestCheckoutCreateMissingBranch(c *C) { 726 w := &Worktree{ 727 r: s.Repository, 728 Filesystem: memfs.New(), 729 } 730 731 err := w.Checkout(&CheckoutOptions{ 732 Create: true, 733 }) 734 735 c.Assert(err, Equals, ErrCreateRequiresBranch) 736} 737 738func (s *WorktreeSuite) TestCheckoutTag(c *C) { 739 f := fixtures.ByTag("tags").One() 740 r := s.NewRepositoryWithEmptyWorktree(f) 741 w, err := r.Worktree() 742 c.Assert(err, IsNil) 743 744 err = w.Checkout(&CheckoutOptions{}) 745 c.Assert(err, IsNil) 746 head, err := w.r.Head() 747 c.Assert(err, IsNil) 748 c.Assert(head.Name().String(), Equals, "refs/heads/master") 749 750 status, err := w.Status() 751 c.Assert(err, IsNil) 752 c.Assert(status.IsClean(), Equals, true) 753 754 err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/lightweight-tag"}) 755 c.Assert(err, IsNil) 756 head, err = w.r.Head() 757 c.Assert(err, IsNil) 758 c.Assert(head.Name().String(), Equals, "HEAD") 759 c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") 760 761 err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/commit-tag"}) 762 c.Assert(err, IsNil) 763 head, err = w.r.Head() 764 c.Assert(err, IsNil) 765 c.Assert(head.Name().String(), Equals, "HEAD") 766 c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") 767 768 err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/tree-tag"}) 769 c.Assert(err, NotNil) 770 head, err = w.r.Head() 771 c.Assert(err, IsNil) 772 c.Assert(head.Name().String(), Equals, "HEAD") 773} 774 775func (s *WorktreeSuite) TestCheckoutBisect(c *C) { 776 if testing.Short() { 777 c.Skip("skipping test in short mode.") 778 } 779 780 s.testCheckoutBisect(c, "https://github.com/src-d/go-git.git") 781} 782 783func (s *WorktreeSuite) TestCheckoutBisectSubmodules(c *C) { 784 s.testCheckoutBisect(c, "https://github.com/git-fixtures/submodule.git") 785} 786 787// TestCheckoutBisect simulates a git bisect going through the git history and 788// checking every commit over the previous commit 789func (s *WorktreeSuite) testCheckoutBisect(c *C, url string) { 790 f := fixtures.ByURL(url).One() 791 r := s.NewRepositoryWithEmptyWorktree(f) 792 793 w, err := r.Worktree() 794 c.Assert(err, IsNil) 795 796 iter, err := w.r.Log(&LogOptions{}) 797 c.Assert(err, IsNil) 798 799 iter.ForEach(func(commit *object.Commit) error { 800 err := w.Checkout(&CheckoutOptions{Hash: commit.Hash}) 801 c.Assert(err, IsNil) 802 803 status, err := w.Status() 804 c.Assert(err, IsNil) 805 c.Assert(status.IsClean(), Equals, true) 806 807 return nil 808 }) 809} 810 811func (s *WorktreeSuite) TestStatus(c *C) { 812 fs := memfs.New() 813 w := &Worktree{ 814 r: s.Repository, 815 Filesystem: fs, 816 } 817 818 status, err := w.Status() 819 c.Assert(err, IsNil) 820 821 c.Assert(status.IsClean(), Equals, false) 822 c.Assert(status, HasLen, 9) 823} 824 825func (s *WorktreeSuite) TestStatusEmpty(c *C) { 826 fs := memfs.New() 827 storage := memory.NewStorage() 828 829 r, err := Init(storage, fs) 830 c.Assert(err, IsNil) 831 832 w, err := r.Worktree() 833 c.Assert(err, IsNil) 834 835 status, err := w.Status() 836 c.Assert(err, IsNil) 837 c.Assert(status.IsClean(), Equals, true) 838 c.Assert(status, NotNil) 839} 840 841func (s *WorktreeSuite) TestStatusEmptyDirty(c *C) { 842 fs := memfs.New() 843 err := util.WriteFile(fs, "foo", []byte("foo"), 0755) 844 c.Assert(err, IsNil) 845 846 storage := memory.NewStorage() 847 848 r, err := Init(storage, fs) 849 c.Assert(err, IsNil) 850 851 w, err := r.Worktree() 852 c.Assert(err, IsNil) 853 854 status, err := w.Status() 855 c.Assert(err, IsNil) 856 c.Assert(status.IsClean(), Equals, false) 857 c.Assert(status, HasLen, 1) 858} 859 860func (s *WorktreeSuite) TestReset(c *C) { 861 fs := memfs.New() 862 w := &Worktree{ 863 r: s.Repository, 864 Filesystem: fs, 865 } 866 867 commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 868 869 err := w.Checkout(&CheckoutOptions{}) 870 c.Assert(err, IsNil) 871 872 branch, err := w.r.Reference(plumbing.Master, false) 873 c.Assert(err, IsNil) 874 c.Assert(branch.Hash(), Not(Equals), commit) 875 876 err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) 877 c.Assert(err, IsNil) 878 879 branch, err = w.r.Reference(plumbing.Master, false) 880 c.Assert(err, IsNil) 881 c.Assert(branch.Hash(), Equals, commit) 882 883 status, err := w.Status() 884 c.Assert(err, IsNil) 885 c.Assert(status.IsClean(), Equals, true) 886} 887 888func (s *WorktreeSuite) TestResetWithUntracked(c *C) { 889 fs := memfs.New() 890 w := &Worktree{ 891 r: s.Repository, 892 Filesystem: fs, 893 } 894 895 commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 896 897 err := w.Checkout(&CheckoutOptions{}) 898 c.Assert(err, IsNil) 899 900 err = util.WriteFile(fs, "foo", nil, 0755) 901 c.Assert(err, IsNil) 902 903 err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) 904 c.Assert(err, IsNil) 905 906 status, err := w.Status() 907 c.Assert(err, IsNil) 908 c.Assert(status.IsClean(), Equals, true) 909} 910 911func (s *WorktreeSuite) TestResetSoft(c *C) { 912 fs := memfs.New() 913 w := &Worktree{ 914 r: s.Repository, 915 Filesystem: fs, 916 } 917 918 commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 919 920 err := w.Checkout(&CheckoutOptions{}) 921 c.Assert(err, IsNil) 922 923 err = w.Reset(&ResetOptions{Mode: SoftReset, Commit: commit}) 924 c.Assert(err, IsNil) 925 926 branch, err := w.r.Reference(plumbing.Master, false) 927 c.Assert(err, IsNil) 928 c.Assert(branch.Hash(), Equals, commit) 929 930 status, err := w.Status() 931 c.Assert(err, IsNil) 932 c.Assert(status.IsClean(), Equals, false) 933 c.Assert(status.File("CHANGELOG").Staging, Equals, Added) 934} 935 936func (s *WorktreeSuite) TestResetMixed(c *C) { 937 fs := memfs.New() 938 w := &Worktree{ 939 r: s.Repository, 940 Filesystem: fs, 941 } 942 943 commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 944 945 err := w.Checkout(&CheckoutOptions{}) 946 c.Assert(err, IsNil) 947 948 err = w.Reset(&ResetOptions{Mode: MixedReset, Commit: commit}) 949 c.Assert(err, IsNil) 950 951 branch, err := w.r.Reference(plumbing.Master, false) 952 c.Assert(err, IsNil) 953 c.Assert(branch.Hash(), Equals, commit) 954 955 status, err := w.Status() 956 c.Assert(err, IsNil) 957 c.Assert(status.IsClean(), Equals, false) 958 c.Assert(status.File("CHANGELOG").Staging, Equals, Untracked) 959} 960 961func (s *WorktreeSuite) TestResetMerge(c *C) { 962 fs := memfs.New() 963 w := &Worktree{ 964 r: s.Repository, 965 Filesystem: fs, 966 } 967 968 commitA := plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294") 969 commitB := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 970 971 err := w.Checkout(&CheckoutOptions{}) 972 c.Assert(err, IsNil) 973 974 err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitA}) 975 c.Assert(err, IsNil) 976 977 branch, err := w.r.Reference(plumbing.Master, false) 978 c.Assert(err, IsNil) 979 c.Assert(branch.Hash(), Equals, commitA) 980 981 f, err := fs.Create(".gitignore") 982 c.Assert(err, IsNil) 983 _, err = f.Write([]byte("foo")) 984 c.Assert(err, IsNil) 985 err = f.Close() 986 c.Assert(err, IsNil) 987 988 err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitB}) 989 c.Assert(err, Equals, ErrUnstagedChanges) 990 991 branch, err = w.r.Reference(plumbing.Master, false) 992 c.Assert(err, IsNil) 993 c.Assert(branch.Hash(), Equals, commitA) 994} 995 996func (s *WorktreeSuite) TestResetHard(c *C) { 997 fs := memfs.New() 998 w := &Worktree{ 999 r: s.Repository, 1000 Filesystem: fs, 1001 } 1002 1003 commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") 1004 1005 err := w.Checkout(&CheckoutOptions{}) 1006 c.Assert(err, IsNil) 1007 1008 f, err := fs.Create(".gitignore") 1009 c.Assert(err, IsNil) 1010 _, err = f.Write([]byte("foo")) 1011 c.Assert(err, IsNil) 1012 err = f.Close() 1013 c.Assert(err, IsNil) 1014 1015 err = w.Reset(&ResetOptions{Mode: HardReset, Commit: commit}) 1016 c.Assert(err, IsNil) 1017 1018 branch, err := w.r.Reference(plumbing.Master, false) 1019 c.Assert(err, IsNil) 1020 c.Assert(branch.Hash(), Equals, commit) 1021} 1022 1023func (s *WorktreeSuite) TestStatusAfterCheckout(c *C) { 1024 fs := memfs.New() 1025 w := &Worktree{ 1026 r: s.Repository, 1027 Filesystem: fs, 1028 } 1029 1030 err := w.Checkout(&CheckoutOptions{Force: true}) 1031 c.Assert(err, IsNil) 1032 1033 status, err := w.Status() 1034 c.Assert(err, IsNil) 1035 c.Assert(status.IsClean(), Equals, true) 1036 1037} 1038 1039func (s *WorktreeSuite) TestStatusModified(c *C) { 1040 fs, clean := s.TemporalFilesystem() 1041 defer clean() 1042 1043 w := &Worktree{ 1044 r: s.Repository, 1045 Filesystem: fs, 1046 } 1047 1048 err := w.Checkout(&CheckoutOptions{}) 1049 c.Assert(err, IsNil) 1050 1051 f, err := fs.Create(".gitignore") 1052 c.Assert(err, IsNil) 1053 _, err = f.Write([]byte("foo")) 1054 c.Assert(err, IsNil) 1055 err = f.Close() 1056 c.Assert(err, IsNil) 1057 1058 status, err := w.Status() 1059 c.Assert(err, IsNil) 1060 c.Assert(status.IsClean(), Equals, false) 1061 c.Assert(status.File(".gitignore").Worktree, Equals, Modified) 1062} 1063 1064func (s *WorktreeSuite) TestStatusIgnored(c *C) { 1065 fs := memfs.New() 1066 w := &Worktree{ 1067 r: s.Repository, 1068 Filesystem: fs, 1069 } 1070 1071 w.Checkout(&CheckoutOptions{}) 1072 1073 fs.MkdirAll("another", os.ModePerm) 1074 f, _ := fs.Create("another/file") 1075 f.Close() 1076 fs.MkdirAll("vendor/github.com", os.ModePerm) 1077 f, _ = fs.Create("vendor/github.com/file") 1078 f.Close() 1079 fs.MkdirAll("vendor/gopkg.in", os.ModePerm) 1080 f, _ = fs.Create("vendor/gopkg.in/file") 1081 f.Close() 1082 1083 status, _ := w.Status() 1084 c.Assert(len(status), Equals, 3) 1085 _, ok := status["another/file"] 1086 c.Assert(ok, Equals, true) 1087 _, ok = status["vendor/github.com/file"] 1088 c.Assert(ok, Equals, true) 1089 _, ok = status["vendor/gopkg.in/file"] 1090 c.Assert(ok, Equals, true) 1091 1092 f, _ = fs.Create(".gitignore") 1093 f.Write([]byte("vendor/g*/")) 1094 f.Close() 1095 f, _ = fs.Create("vendor/.gitignore") 1096 f.Write([]byte("!github.com/\n")) 1097 f.Close() 1098 1099 status, _ = w.Status() 1100 c.Assert(len(status), Equals, 4) 1101 _, ok = status[".gitignore"] 1102 c.Assert(ok, Equals, true) 1103 _, ok = status["another/file"] 1104 c.Assert(ok, Equals, true) 1105 _, ok = status["vendor/.gitignore"] 1106 c.Assert(ok, Equals, true) 1107 _, ok = status["vendor/github.com/file"] 1108 c.Assert(ok, Equals, true) 1109} 1110 1111func (s *WorktreeSuite) TestStatusUntracked(c *C) { 1112 fs := memfs.New() 1113 w := &Worktree{ 1114 r: s.Repository, 1115 Filesystem: fs, 1116 } 1117 1118 err := w.Checkout(&CheckoutOptions{Force: true}) 1119 c.Assert(err, IsNil) 1120 1121 f, err := w.Filesystem.Create("foo") 1122 c.Assert(err, IsNil) 1123 c.Assert(f.Close(), IsNil) 1124 1125 status, err := w.Status() 1126 c.Assert(err, IsNil) 1127 c.Assert(status.File("foo").Staging, Equals, Untracked) 1128 c.Assert(status.File("foo").Worktree, Equals, Untracked) 1129} 1130 1131func (s *WorktreeSuite) TestStatusDeleted(c *C) { 1132 fs, clean := s.TemporalFilesystem() 1133 defer clean() 1134 1135 w := &Worktree{ 1136 r: s.Repository, 1137 Filesystem: fs, 1138 } 1139 1140 err := w.Checkout(&CheckoutOptions{}) 1141 c.Assert(err, IsNil) 1142 1143 err = fs.Remove(".gitignore") 1144 c.Assert(err, IsNil) 1145 1146 status, err := w.Status() 1147 c.Assert(err, IsNil) 1148 c.Assert(status.IsClean(), Equals, false) 1149 c.Assert(status.File(".gitignore").Worktree, Equals, Deleted) 1150} 1151 1152func (s *WorktreeSuite) TestSubmodule(c *C) { 1153 path := fixtures.ByTag("submodule").One().Worktree().Root() 1154 r, err := PlainOpen(path) 1155 c.Assert(err, IsNil) 1156 1157 w, err := r.Worktree() 1158 c.Assert(err, IsNil) 1159 1160 m, err := w.Submodule("basic") 1161 c.Assert(err, IsNil) 1162 1163 c.Assert(m.Config().Name, Equals, "basic") 1164} 1165 1166func (s *WorktreeSuite) TestSubmodules(c *C) { 1167 path := fixtures.ByTag("submodule").One().Worktree().Root() 1168 r, err := PlainOpen(path) 1169 c.Assert(err, IsNil) 1170 1171 w, err := r.Worktree() 1172 c.Assert(err, IsNil) 1173 1174 l, err := w.Submodules() 1175 c.Assert(err, IsNil) 1176 1177 c.Assert(l, HasLen, 2) 1178} 1179 1180func (s *WorktreeSuite) TestAddUntracked(c *C) { 1181 fs := memfs.New() 1182 w := &Worktree{ 1183 r: s.Repository, 1184 Filesystem: fs, 1185 } 1186 1187 err := w.Checkout(&CheckoutOptions{Force: true}) 1188 c.Assert(err, IsNil) 1189 1190 idx, err := w.r.Storer.Index() 1191 c.Assert(err, IsNil) 1192 c.Assert(idx.Entries, HasLen, 9) 1193 1194 err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) 1195 c.Assert(err, IsNil) 1196 1197 hash, err := w.Add("foo") 1198 c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") 1199 c.Assert(err, IsNil) 1200 1201 idx, err = w.r.Storer.Index() 1202 c.Assert(err, IsNil) 1203 c.Assert(idx.Entries, HasLen, 10) 1204 1205 e, err := idx.Entry("foo") 1206 c.Assert(err, IsNil) 1207 c.Assert(e.Hash, Equals, hash) 1208 c.Assert(e.Mode, Equals, filemode.Executable) 1209 1210 status, err := w.Status() 1211 c.Assert(err, IsNil) 1212 c.Assert(status, HasLen, 1) 1213 1214 file := status.File("foo") 1215 c.Assert(file.Staging, Equals, Added) 1216 c.Assert(file.Worktree, Equals, Unmodified) 1217 1218 obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, hash) 1219 c.Assert(err, IsNil) 1220 c.Assert(obj, NotNil) 1221 c.Assert(obj.Size(), Equals, int64(3)) 1222} 1223 1224func (s *WorktreeSuite) TestIgnored(c *C) { 1225 fs := memfs.New() 1226 w := &Worktree{ 1227 r: s.Repository, 1228 Filesystem: fs, 1229 } 1230 1231 w.Excludes = make([]gitignore.Pattern, 0) 1232 w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) 1233 1234 err := w.Checkout(&CheckoutOptions{Force: true}) 1235 c.Assert(err, IsNil) 1236 1237 idx, err := w.r.Storer.Index() 1238 c.Assert(err, IsNil) 1239 c.Assert(idx.Entries, HasLen, 9) 1240 1241 err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) 1242 c.Assert(err, IsNil) 1243 1244 status, err := w.Status() 1245 c.Assert(err, IsNil) 1246 c.Assert(status, HasLen, 0) 1247 1248 file := status.File("foo") 1249 c.Assert(file.Staging, Equals, Untracked) 1250 c.Assert(file.Worktree, Equals, Untracked) 1251} 1252 1253func (s *WorktreeSuite) TestExcludedNoGitignore(c *C) { 1254 f := fixtures.ByTag("empty").One() 1255 r := s.NewRepository(f) 1256 1257 fs := memfs.New() 1258 w := &Worktree{ 1259 r: r, 1260 Filesystem: fs, 1261 } 1262 1263 _, err := fs.Open(".gitignore") 1264 c.Assert(err, Equals, os.ErrNotExist) 1265 1266 w.Excludes = make([]gitignore.Pattern, 0) 1267 w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) 1268 1269 err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) 1270 c.Assert(err, IsNil) 1271 1272 status, err := w.Status() 1273 c.Assert(err, IsNil) 1274 c.Assert(status, HasLen, 0) 1275 1276 file := status.File("foo") 1277 c.Assert(file.Staging, Equals, Untracked) 1278 c.Assert(file.Worktree, Equals, Untracked) 1279} 1280 1281func (s *WorktreeSuite) TestAddModified(c *C) { 1282 fs := memfs.New() 1283 w := &Worktree{ 1284 r: s.Repository, 1285 Filesystem: fs, 1286 } 1287 1288 err := w.Checkout(&CheckoutOptions{Force: true}) 1289 c.Assert(err, IsNil) 1290 1291 idx, err := w.r.Storer.Index() 1292 c.Assert(err, IsNil) 1293 c.Assert(idx.Entries, HasLen, 9) 1294 1295 err = util.WriteFile(w.Filesystem, "LICENSE", []byte("FOO"), 0644) 1296 c.Assert(err, IsNil) 1297 1298 hash, err := w.Add("LICENSE") 1299 c.Assert(err, IsNil) 1300 c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") 1301 1302 idx, err = w.r.Storer.Index() 1303 c.Assert(err, IsNil) 1304 c.Assert(idx.Entries, HasLen, 9) 1305 1306 e, err := idx.Entry("LICENSE") 1307 c.Assert(err, IsNil) 1308 c.Assert(e.Hash, Equals, hash) 1309 c.Assert(e.Mode, Equals, filemode.Regular) 1310 1311 status, err := w.Status() 1312 c.Assert(err, IsNil) 1313 c.Assert(status, HasLen, 1) 1314 1315 file := status.File("LICENSE") 1316 c.Assert(file.Staging, Equals, Modified) 1317 c.Assert(file.Worktree, Equals, Unmodified) 1318} 1319 1320func (s *WorktreeSuite) TestAddUnmodified(c *C) { 1321 fs := memfs.New() 1322 w := &Worktree{ 1323 r: s.Repository, 1324 Filesystem: fs, 1325 } 1326 1327 err := w.Checkout(&CheckoutOptions{Force: true}) 1328 c.Assert(err, IsNil) 1329 1330 hash, err := w.Add("LICENSE") 1331 c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") 1332 c.Assert(err, IsNil) 1333} 1334 1335func (s *WorktreeSuite) TestAddRemoved(c *C) { 1336 fs := memfs.New() 1337 w := &Worktree{ 1338 r: s.Repository, 1339 Filesystem: fs, 1340 } 1341 1342 err := w.Checkout(&CheckoutOptions{Force: true}) 1343 c.Assert(err, IsNil) 1344 1345 idx, err := w.r.Storer.Index() 1346 c.Assert(err, IsNil) 1347 c.Assert(idx.Entries, HasLen, 9) 1348 1349 err = w.Filesystem.Remove("LICENSE") 1350 c.Assert(err, IsNil) 1351 1352 hash, err := w.Add("LICENSE") 1353 c.Assert(err, IsNil) 1354 c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") 1355 1356 e, err := idx.Entry("LICENSE") 1357 c.Assert(err, IsNil) 1358 c.Assert(e.Hash, Equals, hash) 1359 c.Assert(e.Mode, Equals, filemode.Regular) 1360 1361 status, err := w.Status() 1362 c.Assert(err, IsNil) 1363 c.Assert(status, HasLen, 1) 1364 1365 file := status.File("LICENSE") 1366 c.Assert(file.Staging, Equals, Deleted) 1367} 1368 1369func (s *WorktreeSuite) TestAddSymlink(c *C) { 1370 dir, clean := s.TemporalDir() 1371 defer clean() 1372 1373 r, err := PlainInit(dir, false) 1374 c.Assert(err, IsNil) 1375 err = util.WriteFile(r.wt, "foo", []byte("qux"), 0644) 1376 c.Assert(err, IsNil) 1377 err = r.wt.Symlink("foo", "bar") 1378 c.Assert(err, IsNil) 1379 1380 w, err := r.Worktree() 1381 c.Assert(err, IsNil) 1382 h, err := w.Add("foo") 1383 c.Assert(err, IsNil) 1384 c.Assert(h, Not(Equals), plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) 1385 1386 h, err = w.Add("bar") 1387 c.Assert(err, IsNil) 1388 c.Assert(h, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) 1389 1390 obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, h) 1391 c.Assert(err, IsNil) 1392 c.Assert(obj, NotNil) 1393 c.Assert(obj.Size(), Equals, int64(3)) 1394} 1395 1396func (s *WorktreeSuite) TestAddDirectory(c *C) { 1397 fs := memfs.New() 1398 w := &Worktree{ 1399 r: s.Repository, 1400 Filesystem: fs, 1401 } 1402 1403 err := w.Checkout(&CheckoutOptions{Force: true}) 1404 c.Assert(err, IsNil) 1405 1406 idx, err := w.r.Storer.Index() 1407 c.Assert(err, IsNil) 1408 c.Assert(idx.Entries, HasLen, 9) 1409 1410 err = util.WriteFile(w.Filesystem, "qux/foo", []byte("FOO"), 0755) 1411 c.Assert(err, IsNil) 1412 err = util.WriteFile(w.Filesystem, "qux/baz/bar", []byte("BAR"), 0755) 1413 c.Assert(err, IsNil) 1414 1415 h, err := w.Add("qux") 1416 c.Assert(err, IsNil) 1417 c.Assert(h.IsZero(), Equals, true) 1418 1419 idx, err = w.r.Storer.Index() 1420 c.Assert(err, IsNil) 1421 c.Assert(idx.Entries, HasLen, 11) 1422 1423 e, err := idx.Entry("qux/foo") 1424 c.Assert(err, IsNil) 1425 c.Assert(e.Mode, Equals, filemode.Executable) 1426 1427 e, err = idx.Entry("qux/baz/bar") 1428 c.Assert(err, IsNil) 1429 c.Assert(e.Mode, Equals, filemode.Executable) 1430 1431 status, err := w.Status() 1432 c.Assert(err, IsNil) 1433 c.Assert(status, HasLen, 2) 1434 1435 file := status.File("qux/foo") 1436 c.Assert(file.Staging, Equals, Added) 1437 c.Assert(file.Worktree, Equals, Unmodified) 1438 1439 file = status.File("qux/baz/bar") 1440 c.Assert(file.Staging, Equals, Added) 1441 c.Assert(file.Worktree, Equals, Unmodified) 1442} 1443 1444func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) { 1445 r, _ := Init(memory.NewStorage(), memfs.New()) 1446 w, _ := r.Worktree() 1447 1448 h, err := w.Add("foo") 1449 c.Assert(err, NotNil) 1450 c.Assert(h.IsZero(), Equals, true) 1451} 1452 1453func (s *WorktreeSuite) TestAddAll(c *C) { 1454 fs := memfs.New() 1455 w := &Worktree{ 1456 r: s.Repository, 1457 Filesystem: fs, 1458 } 1459 1460 err := w.Checkout(&CheckoutOptions{Force: true}) 1461 c.Assert(err, IsNil) 1462 1463 idx, err := w.r.Storer.Index() 1464 c.Assert(err, IsNil) 1465 c.Assert(idx.Entries, HasLen, 9) 1466 1467 err = util.WriteFile(w.Filesystem, "file1", []byte("file1"), 0644) 1468 c.Assert(err, IsNil) 1469 1470 err = util.WriteFile(w.Filesystem, "file2", []byte("file2"), 0644) 1471 c.Assert(err, IsNil) 1472 1473 err = util.WriteFile(w.Filesystem, "file3", []byte("ignore me"), 0644) 1474 c.Assert(err, IsNil) 1475 1476 w.Excludes = make([]gitignore.Pattern, 0) 1477 w.Excludes = append(w.Excludes, gitignore.ParsePattern("file3", nil)) 1478 1479 err = w.AddWithOptions(&AddOptions{All: true}) 1480 c.Assert(err, IsNil) 1481 1482 idx, err = w.r.Storer.Index() 1483 c.Assert(err, IsNil) 1484 c.Assert(idx.Entries, HasLen, 11) 1485 1486 status, err := w.Status() 1487 c.Assert(err, IsNil) 1488 c.Assert(status, HasLen, 2) 1489 1490 file1 := status.File("file1") 1491 c.Assert(file1.Staging, Equals, Added) 1492 file2 := status.File("file2") 1493 c.Assert(file2.Staging, Equals, Added) 1494 file3 := status.File("file3") 1495 c.Assert(file3.Staging, Equals, Untracked) 1496 c.Assert(file3.Worktree, Equals, Untracked) 1497} 1498 1499func (s *WorktreeSuite) TestAddGlob(c *C) { 1500 fs := memfs.New() 1501 w := &Worktree{ 1502 r: s.Repository, 1503 Filesystem: fs, 1504 } 1505 1506 err := w.Checkout(&CheckoutOptions{Force: true}) 1507 c.Assert(err, IsNil) 1508 1509 idx, err := w.r.Storer.Index() 1510 c.Assert(err, IsNil) 1511 c.Assert(idx.Entries, HasLen, 9) 1512 1513 err = util.WriteFile(w.Filesystem, "qux/qux", []byte("QUX"), 0755) 1514 c.Assert(err, IsNil) 1515 err = util.WriteFile(w.Filesystem, "qux/baz", []byte("BAZ"), 0755) 1516 c.Assert(err, IsNil) 1517 err = util.WriteFile(w.Filesystem, "qux/bar/baz", []byte("BAZ"), 0755) 1518 c.Assert(err, IsNil) 1519 1520 err = w.AddWithOptions(&AddOptions{Glob: w.Filesystem.Join("qux", "b*")}) 1521 c.Assert(err, IsNil) 1522 1523 idx, err = w.r.Storer.Index() 1524 c.Assert(err, IsNil) 1525 c.Assert(idx.Entries, HasLen, 11) 1526 1527 e, err := idx.Entry("qux/baz") 1528 c.Assert(err, IsNil) 1529 c.Assert(e.Mode, Equals, filemode.Executable) 1530 1531 e, err = idx.Entry("qux/bar/baz") 1532 c.Assert(err, IsNil) 1533 c.Assert(e.Mode, Equals, filemode.Executable) 1534 1535 status, err := w.Status() 1536 c.Assert(err, IsNil) 1537 c.Assert(status, HasLen, 3) 1538 1539 file := status.File("qux/qux") 1540 c.Assert(file.Staging, Equals, Untracked) 1541 c.Assert(file.Worktree, Equals, Untracked) 1542 1543 file = status.File("qux/baz") 1544 c.Assert(file.Staging, Equals, Added) 1545 c.Assert(file.Worktree, Equals, Unmodified) 1546 1547 file = status.File("qux/bar/baz") 1548 c.Assert(file.Staging, Equals, Added) 1549 c.Assert(file.Worktree, Equals, Unmodified) 1550} 1551 1552func (s *WorktreeSuite) TestAddGlobErrorNoMatches(c *C) { 1553 r, _ := Init(memory.NewStorage(), memfs.New()) 1554 w, _ := r.Worktree() 1555 1556 err := w.AddGlob("foo") 1557 c.Assert(err, Equals, ErrGlobNoMatches) 1558} 1559 1560func (s *WorktreeSuite) TestRemove(c *C) { 1561 fs := memfs.New() 1562 w := &Worktree{ 1563 r: s.Repository, 1564 Filesystem: fs, 1565 } 1566 1567 err := w.Checkout(&CheckoutOptions{Force: true}) 1568 c.Assert(err, IsNil) 1569 1570 hash, err := w.Remove("LICENSE") 1571 c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") 1572 c.Assert(err, IsNil) 1573 1574 status, err := w.Status() 1575 c.Assert(err, IsNil) 1576 c.Assert(status, HasLen, 1) 1577 c.Assert(status.File("LICENSE").Staging, Equals, Deleted) 1578} 1579 1580func (s *WorktreeSuite) TestRemoveNotExistentEntry(c *C) { 1581 fs := memfs.New() 1582 w := &Worktree{ 1583 r: s.Repository, 1584 Filesystem: fs, 1585 } 1586 1587 err := w.Checkout(&CheckoutOptions{Force: true}) 1588 c.Assert(err, IsNil) 1589 1590 hash, err := w.Remove("not-exists") 1591 c.Assert(hash.IsZero(), Equals, true) 1592 c.Assert(err, NotNil) 1593} 1594 1595func (s *WorktreeSuite) TestRemoveDirectory(c *C) { 1596 fs := memfs.New() 1597 w := &Worktree{ 1598 r: s.Repository, 1599 Filesystem: fs, 1600 } 1601 1602 err := w.Checkout(&CheckoutOptions{Force: true}) 1603 c.Assert(err, IsNil) 1604 1605 hash, err := w.Remove("json") 1606 c.Assert(hash.IsZero(), Equals, true) 1607 c.Assert(err, IsNil) 1608 1609 status, err := w.Status() 1610 c.Assert(err, IsNil) 1611 c.Assert(status, HasLen, 2) 1612 c.Assert(status.File("json/long.json").Staging, Equals, Deleted) 1613 c.Assert(status.File("json/short.json").Staging, Equals, Deleted) 1614 1615 _, err = w.Filesystem.Stat("json") 1616 c.Assert(os.IsNotExist(err), Equals, true) 1617} 1618 1619func (s *WorktreeSuite) TestRemoveDirectoryUntracked(c *C) { 1620 fs := memfs.New() 1621 w := &Worktree{ 1622 r: s.Repository, 1623 Filesystem: fs, 1624 } 1625 1626 err := w.Checkout(&CheckoutOptions{Force: true}) 1627 c.Assert(err, IsNil) 1628 1629 err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) 1630 c.Assert(err, IsNil) 1631 1632 hash, err := w.Remove("json") 1633 c.Assert(hash.IsZero(), Equals, true) 1634 c.Assert(err, IsNil) 1635 1636 status, err := w.Status() 1637 c.Assert(err, IsNil) 1638 c.Assert(status, HasLen, 3) 1639 c.Assert(status.File("json/long.json").Staging, Equals, Deleted) 1640 c.Assert(status.File("json/short.json").Staging, Equals, Deleted) 1641 c.Assert(status.File("json/foo").Staging, Equals, Untracked) 1642 1643 _, err = w.Filesystem.Stat("json") 1644 c.Assert(err, IsNil) 1645} 1646 1647func (s *WorktreeSuite) TestRemoveDeletedFromWorktree(c *C) { 1648 fs := memfs.New() 1649 w := &Worktree{ 1650 r: s.Repository, 1651 Filesystem: fs, 1652 } 1653 1654 err := w.Checkout(&CheckoutOptions{Force: true}) 1655 c.Assert(err, IsNil) 1656 1657 err = fs.Remove("LICENSE") 1658 c.Assert(err, IsNil) 1659 1660 hash, err := w.Remove("LICENSE") 1661 c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") 1662 c.Assert(err, IsNil) 1663 1664 status, err := w.Status() 1665 c.Assert(err, IsNil) 1666 c.Assert(status, HasLen, 1) 1667 c.Assert(status.File("LICENSE").Staging, Equals, Deleted) 1668} 1669 1670func (s *WorktreeSuite) TestRemoveGlob(c *C) { 1671 fs := memfs.New() 1672 w := &Worktree{ 1673 r: s.Repository, 1674 Filesystem: fs, 1675 } 1676 1677 err := w.Checkout(&CheckoutOptions{Force: true}) 1678 c.Assert(err, IsNil) 1679 1680 err = w.RemoveGlob(w.Filesystem.Join("json", "l*")) 1681 c.Assert(err, IsNil) 1682 1683 status, err := w.Status() 1684 c.Assert(err, IsNil) 1685 c.Assert(status, HasLen, 1) 1686 c.Assert(status.File("json/long.json").Staging, Equals, Deleted) 1687} 1688 1689func (s *WorktreeSuite) TestRemoveGlobDirectory(c *C) { 1690 fs := memfs.New() 1691 w := &Worktree{ 1692 r: s.Repository, 1693 Filesystem: fs, 1694 } 1695 1696 err := w.Checkout(&CheckoutOptions{Force: true}) 1697 c.Assert(err, IsNil) 1698 1699 err = w.RemoveGlob("js*") 1700 c.Assert(err, IsNil) 1701 1702 status, err := w.Status() 1703 c.Assert(err, IsNil) 1704 c.Assert(status, HasLen, 2) 1705 c.Assert(status.File("json/short.json").Staging, Equals, Deleted) 1706 c.Assert(status.File("json/long.json").Staging, Equals, Deleted) 1707 1708 _, err = w.Filesystem.Stat("json") 1709 c.Assert(os.IsNotExist(err), Equals, true) 1710} 1711 1712func (s *WorktreeSuite) TestRemoveGlobDirectoryDeleted(c *C) { 1713 fs := memfs.New() 1714 w := &Worktree{ 1715 r: s.Repository, 1716 Filesystem: fs, 1717 } 1718 1719 err := w.Checkout(&CheckoutOptions{Force: true}) 1720 c.Assert(err, IsNil) 1721 1722 err = fs.Remove("json/short.json") 1723 c.Assert(err, IsNil) 1724 1725 err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) 1726 c.Assert(err, IsNil) 1727 1728 err = w.RemoveGlob("js*") 1729 c.Assert(err, IsNil) 1730 1731 status, err := w.Status() 1732 c.Assert(err, IsNil) 1733 c.Assert(status, HasLen, 3) 1734 c.Assert(status.File("json/short.json").Staging, Equals, Deleted) 1735 c.Assert(status.File("json/long.json").Staging, Equals, Deleted) 1736} 1737 1738func (s *WorktreeSuite) TestMove(c *C) { 1739 fs := memfs.New() 1740 w := &Worktree{ 1741 r: s.Repository, 1742 Filesystem: fs, 1743 } 1744 1745 err := w.Checkout(&CheckoutOptions{Force: true}) 1746 c.Assert(err, IsNil) 1747 1748 hash, err := w.Move("LICENSE", "foo") 1749 c.Check(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") 1750 c.Assert(err, IsNil) 1751 1752 status, err := w.Status() 1753 c.Assert(err, IsNil) 1754 c.Assert(status, HasLen, 2) 1755 c.Assert(status.File("LICENSE").Staging, Equals, Deleted) 1756 c.Assert(status.File("foo").Staging, Equals, Added) 1757 1758} 1759 1760func (s *WorktreeSuite) TestMoveNotExistentEntry(c *C) { 1761 fs := memfs.New() 1762 w := &Worktree{ 1763 r: s.Repository, 1764 Filesystem: fs, 1765 } 1766 1767 err := w.Checkout(&CheckoutOptions{Force: true}) 1768 c.Assert(err, IsNil) 1769 1770 hash, err := w.Move("not-exists", "foo") 1771 c.Assert(hash.IsZero(), Equals, true) 1772 c.Assert(err, NotNil) 1773} 1774 1775func (s *WorktreeSuite) TestMoveToExistent(c *C) { 1776 fs := memfs.New() 1777 w := &Worktree{ 1778 r: s.Repository, 1779 Filesystem: fs, 1780 } 1781 1782 err := w.Checkout(&CheckoutOptions{Force: true}) 1783 c.Assert(err, IsNil) 1784 1785 hash, err := w.Move(".gitignore", "LICENSE") 1786 c.Assert(hash.IsZero(), Equals, true) 1787 c.Assert(err, Equals, ErrDestinationExists) 1788} 1789 1790func (s *WorktreeSuite) TestClean(c *C) { 1791 fs := fixtures.ByTag("dirty").One().Worktree() 1792 1793 // Open the repo. 1794 fs, err := fs.Chroot("repo") 1795 c.Assert(err, IsNil) 1796 r, err := PlainOpen(fs.Root()) 1797 c.Assert(err, IsNil) 1798 1799 wt, err := r.Worktree() 1800 c.Assert(err, IsNil) 1801 1802 // Status before cleaning. 1803 status, err := wt.Status() 1804 c.Assert(err, IsNil) 1805 c.Assert(len(status), Equals, 2) 1806 1807 err = wt.Clean(&CleanOptions{}) 1808 c.Assert(err, IsNil) 1809 1810 // Status after cleaning. 1811 status, err = wt.Status() 1812 c.Assert(err, IsNil) 1813 1814 c.Assert(len(status), Equals, 1) 1815 1816 fi, err := fs.Lstat("pkgA") 1817 c.Assert(err, IsNil) 1818 c.Assert(fi.IsDir(), Equals, true) 1819 1820 // Clean with Dir: true. 1821 err = wt.Clean(&CleanOptions{Dir: true}) 1822 c.Assert(err, IsNil) 1823 1824 status, err = wt.Status() 1825 c.Assert(err, IsNil) 1826 1827 c.Assert(len(status), Equals, 0) 1828 1829 // An empty dir should be deleted, as well. 1830 _, err = fs.Lstat("pkgA") 1831 c.Assert(err, ErrorMatches, ".*(no such file or directory.*|.*file does not exist)*.") 1832} 1833 1834func (s *WorktreeSuite) TestCleanBare(c *C) { 1835 storer := memory.NewStorage() 1836 1837 r, err := Init(storer, nil) 1838 c.Assert(err, IsNil) 1839 c.Assert(r, NotNil) 1840 1841 wtfs := memfs.New() 1842 1843 err = wtfs.MkdirAll("worktree", os.ModePerm) 1844 c.Assert(err, IsNil) 1845 1846 wtfs, err = wtfs.Chroot("worktree") 1847 c.Assert(err, IsNil) 1848 1849 r, err = Open(storer, wtfs) 1850 c.Assert(err, IsNil) 1851 1852 wt, err := r.Worktree() 1853 c.Assert(err, IsNil) 1854 1855 _, err = wt.Filesystem.Lstat(".") 1856 c.Assert(err, IsNil) 1857 1858 // Clean with Dir: true. 1859 err = wt.Clean(&CleanOptions{Dir: true}) 1860 c.Assert(err, IsNil) 1861 1862 // Root worktree directory must remain after cleaning 1863 _, err = wt.Filesystem.Lstat(".") 1864 c.Assert(err, IsNil) 1865} 1866 1867func (s *WorktreeSuite) TestAlternatesRepo(c *C) { 1868 fs := fixtures.ByTag("alternates").One().Worktree() 1869 1870 // Open 1st repo. 1871 rep1fs, err := fs.Chroot("rep1") 1872 c.Assert(err, IsNil) 1873 rep1, err := PlainOpen(rep1fs.Root()) 1874 c.Assert(err, IsNil) 1875 1876 // Open 2nd repo. 1877 rep2fs, err := fs.Chroot("rep2") 1878 c.Assert(err, IsNil) 1879 rep2, err := PlainOpen(rep2fs.Root()) 1880 c.Assert(err, IsNil) 1881 1882 // Get the HEAD commit from the main repo. 1883 h, err := rep1.Head() 1884 c.Assert(err, IsNil) 1885 commit1, err := rep1.CommitObject(h.Hash()) 1886 c.Assert(err, IsNil) 1887 1888 // Get the HEAD commit from the shared repo. 1889 h, err = rep2.Head() 1890 c.Assert(err, IsNil) 1891 commit2, err := rep2.CommitObject(h.Hash()) 1892 c.Assert(err, IsNil) 1893 1894 c.Assert(commit1.String(), Equals, commit2.String()) 1895} 1896 1897func (s *WorktreeSuite) TestGrep(c *C) { 1898 cases := []struct { 1899 name string 1900 options GrepOptions 1901 wantResult []GrepResult 1902 dontWantResult []GrepResult 1903 wantError error 1904 }{ 1905 { 1906 name: "basic word match", 1907 options: GrepOptions{ 1908 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 1909 }, 1910 wantResult: []GrepResult{ 1911 { 1912 FileName: "go/example.go", 1913 LineNumber: 3, 1914 Content: "import (", 1915 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1916 }, 1917 { 1918 FileName: "vendor/foo.go", 1919 LineNumber: 3, 1920 Content: "import \"fmt\"", 1921 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1922 }, 1923 }, 1924 }, { 1925 name: "case insensitive match", 1926 options: GrepOptions{ 1927 Patterns: []*regexp.Regexp{regexp.MustCompile(`(?i)IMport`)}, 1928 }, 1929 wantResult: []GrepResult{ 1930 { 1931 FileName: "go/example.go", 1932 LineNumber: 3, 1933 Content: "import (", 1934 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1935 }, 1936 { 1937 FileName: "vendor/foo.go", 1938 LineNumber: 3, 1939 Content: "import \"fmt\"", 1940 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1941 }, 1942 }, 1943 }, { 1944 name: "invert match", 1945 options: GrepOptions{ 1946 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 1947 InvertMatch: true, 1948 }, 1949 dontWantResult: []GrepResult{ 1950 { 1951 FileName: "go/example.go", 1952 LineNumber: 3, 1953 Content: "import (", 1954 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1955 }, 1956 { 1957 FileName: "vendor/foo.go", 1958 LineNumber: 3, 1959 Content: "import \"fmt\"", 1960 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1961 }, 1962 }, 1963 }, { 1964 name: "match at a given commit hash", 1965 options: GrepOptions{ 1966 Patterns: []*regexp.Regexp{regexp.MustCompile("The MIT License")}, 1967 CommitHash: plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 1968 }, 1969 wantResult: []GrepResult{ 1970 { 1971 FileName: "LICENSE", 1972 LineNumber: 1, 1973 Content: "The MIT License (MIT)", 1974 TreeName: "b029517f6300c2da0f4b651b8642506cd6aaf45d", 1975 }, 1976 }, 1977 dontWantResult: []GrepResult{ 1978 { 1979 FileName: "go/example.go", 1980 LineNumber: 3, 1981 Content: "import (", 1982 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1983 }, 1984 }, 1985 }, { 1986 name: "match for a given pathspec", 1987 options: GrepOptions{ 1988 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 1989 PathSpecs: []*regexp.Regexp{regexp.MustCompile("go/")}, 1990 }, 1991 wantResult: []GrepResult{ 1992 { 1993 FileName: "go/example.go", 1994 LineNumber: 3, 1995 Content: "import (", 1996 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1997 }, 1998 }, 1999 dontWantResult: []GrepResult{ 2000 { 2001 FileName: "vendor/foo.go", 2002 LineNumber: 3, 2003 Content: "import \"fmt\"", 2004 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2005 }, 2006 }, 2007 }, { 2008 name: "match at a given reference name", 2009 options: GrepOptions{ 2010 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 2011 ReferenceName: "refs/heads/master", 2012 }, 2013 wantResult: []GrepResult{ 2014 { 2015 FileName: "go/example.go", 2016 LineNumber: 3, 2017 Content: "import (", 2018 TreeName: "refs/heads/master", 2019 }, 2020 }, 2021 }, { 2022 name: "ambiguous options", 2023 options: GrepOptions{ 2024 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 2025 CommitHash: plumbing.NewHash("2d55a722f3c3ecc36da919dfd8b6de38352f3507"), 2026 ReferenceName: "somereferencename", 2027 }, 2028 wantError: ErrHashOrReference, 2029 }, { 2030 name: "multiple patterns", 2031 options: GrepOptions{ 2032 Patterns: []*regexp.Regexp{ 2033 regexp.MustCompile("import"), 2034 regexp.MustCompile("License"), 2035 }, 2036 }, 2037 wantResult: []GrepResult{ 2038 { 2039 FileName: "go/example.go", 2040 LineNumber: 3, 2041 Content: "import (", 2042 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2043 }, 2044 { 2045 FileName: "vendor/foo.go", 2046 LineNumber: 3, 2047 Content: "import \"fmt\"", 2048 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2049 }, 2050 { 2051 FileName: "LICENSE", 2052 LineNumber: 1, 2053 Content: "The MIT License (MIT)", 2054 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2055 }, 2056 }, 2057 }, { 2058 name: "multiple pathspecs", 2059 options: GrepOptions{ 2060 Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, 2061 PathSpecs: []*regexp.Regexp{ 2062 regexp.MustCompile("go/"), 2063 regexp.MustCompile("vendor/"), 2064 }, 2065 }, 2066 wantResult: []GrepResult{ 2067 { 2068 FileName: "go/example.go", 2069 LineNumber: 3, 2070 Content: "import (", 2071 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2072 }, 2073 { 2074 FileName: "vendor/foo.go", 2075 LineNumber: 3, 2076 Content: "import \"fmt\"", 2077 TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2078 }, 2079 }, 2080 }, 2081 } 2082 2083 path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() 2084 2085 dir, clean := s.TemporalDir() 2086 defer clean() 2087 2088 server, err := PlainClone(dir, false, &CloneOptions{ 2089 URL: path, 2090 }) 2091 c.Assert(err, IsNil) 2092 2093 w, err := server.Worktree() 2094 c.Assert(err, IsNil) 2095 2096 for _, tc := range cases { 2097 gr, err := w.Grep(&tc.options) 2098 if tc.wantError != nil { 2099 c.Assert(err, Equals, tc.wantError) 2100 } else { 2101 c.Assert(err, IsNil) 2102 } 2103 2104 // Iterate through the results and check if the wanted result is present 2105 // in the got result. 2106 for _, wantResult := range tc.wantResult { 2107 found := false 2108 for _, gotResult := range gr { 2109 if wantResult == gotResult { 2110 found = true 2111 break 2112 } 2113 } 2114 if !found { 2115 c.Errorf("unexpected grep results for %q, expected result to contain: %v", tc.name, wantResult) 2116 } 2117 } 2118 2119 // Iterate through the results and check if the not wanted result is 2120 // present in the got result. 2121 for _, dontWantResult := range tc.dontWantResult { 2122 found := false 2123 for _, gotResult := range gr { 2124 if dontWantResult == gotResult { 2125 found = true 2126 break 2127 } 2128 } 2129 if found { 2130 c.Errorf("unexpected grep results for %q, expected result to NOT contain: %v", tc.name, dontWantResult) 2131 } 2132 } 2133 } 2134} 2135 2136func (s *WorktreeSuite) TestAddAndCommit(c *C) { 2137 dir, clean := s.TemporalDir() 2138 defer clean() 2139 2140 repo, err := PlainInit(dir, false) 2141 c.Assert(err, IsNil) 2142 2143 w, err := repo.Worktree() 2144 c.Assert(err, IsNil) 2145 2146 _, err = w.Add(".") 2147 c.Assert(err, IsNil) 2148 2149 w.Commit("Test Add And Commit", &CommitOptions{Author: &object.Signature{ 2150 Name: "foo", 2151 Email: "foo@foo.foo", 2152 When: time.Now(), 2153 }}) 2154 2155 iter, err := w.r.Log(&LogOptions{}) 2156 c.Assert(err, IsNil) 2157 err = iter.ForEach(func(c *object.Commit) error { 2158 files, err := c.Files() 2159 if err != nil { 2160 return err 2161 } 2162 2163 err = files.ForEach(func(f *object.File) error { 2164 return errors.New("Expected no files, got at least 1") 2165 }) 2166 return err 2167 }) 2168 c.Assert(err, IsNil) 2169} 2170 2171func (s *WorktreeSuite) TestLinkedWorktree(c *C) { 2172 fs := fixtures.ByTag("linked-worktree").One().Worktree() 2173 2174 // Open main repo. 2175 { 2176 fs, err := fs.Chroot("main") 2177 c.Assert(err, IsNil) 2178 repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true}) 2179 c.Assert(err, IsNil) 2180 2181 wt, err := repo.Worktree() 2182 c.Assert(err, IsNil) 2183 2184 status, err := wt.Status() 2185 c.Assert(err, IsNil) 2186 c.Assert(len(status), Equals, 2) // 2 files 2187 2188 head, err := repo.Head() 2189 c.Assert(err, IsNil) 2190 c.Assert(string(head.Name()), Equals, "refs/heads/master") 2191 } 2192 2193 // Open linked-worktree #1. 2194 { 2195 fs, err := fs.Chroot("linked-worktree-1") 2196 c.Assert(err, IsNil) 2197 repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true}) 2198 c.Assert(err, IsNil) 2199 2200 wt, err := repo.Worktree() 2201 c.Assert(err, IsNil) 2202 2203 status, err := wt.Status() 2204 c.Assert(err, IsNil) 2205 c.Assert(len(status), Equals, 3) // 3 files 2206 2207 _, ok := status["linked-worktree-1-unique-file.txt"] 2208 c.Assert(ok, Equals, true) 2209 2210 head, err := repo.Head() 2211 c.Assert(err, IsNil) 2212 c.Assert(string(head.Name()), Equals, "refs/heads/linked-worktree-1") 2213 } 2214 2215 // Open linked-worktree #2. 2216 { 2217 fs, err := fs.Chroot("linked-worktree-2") 2218 c.Assert(err, IsNil) 2219 repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true}) 2220 c.Assert(err, IsNil) 2221 2222 wt, err := repo.Worktree() 2223 c.Assert(err, IsNil) 2224 2225 status, err := wt.Status() 2226 c.Assert(err, IsNil) 2227 c.Assert(len(status), Equals, 3) // 3 files 2228 2229 _, ok := status["linked-worktree-2-unique-file.txt"] 2230 c.Assert(ok, Equals, true) 2231 2232 head, err := repo.Head() 2233 c.Assert(err, IsNil) 2234 c.Assert(string(head.Name()), Equals, "refs/heads/branch-with-different-name") 2235 } 2236 2237 // Open linked-worktree #2. 2238 { 2239 fs, err := fs.Chroot("linked-worktree-invalid-commondir") 2240 c.Assert(err, IsNil) 2241 _, err = PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true}) 2242 c.Assert(err, Equals, ErrRepositoryIncomplete) 2243 } 2244}