fork of go-git with some jj specific features
1
fork

Configure Feed

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

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