You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

repository.go 40KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614
  1. package git
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. stdioutil "io/ioutil"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "strings"
  13. "time"
  14. "github.com/go-git/go-git/v5/config"
  15. "github.com/go-git/go-git/v5/internal/revision"
  16. "github.com/go-git/go-git/v5/plumbing"
  17. "github.com/go-git/go-git/v5/plumbing/cache"
  18. "github.com/go-git/go-git/v5/plumbing/format/packfile"
  19. "github.com/go-git/go-git/v5/plumbing/object"
  20. "github.com/go-git/go-git/v5/plumbing/storer"
  21. "github.com/go-git/go-git/v5/storage"
  22. "github.com/go-git/go-git/v5/storage/filesystem"
  23. "github.com/go-git/go-git/v5/utils/ioutil"
  24. "github.com/imdario/mergo"
  25. "golang.org/x/crypto/openpgp"
  26. "github.com/go-git/go-billy/v5"
  27. "github.com/go-git/go-billy/v5/osfs"
  28. )
  29. // GitDirName this is a special folder where all the git stuff is.
  30. const GitDirName = ".git"
  31. var (
  32. // ErrBranchExists an error stating the specified branch already exists
  33. ErrBranchExists = errors.New("branch already exists")
  34. // ErrBranchNotFound an error stating the specified branch does not exist
  35. ErrBranchNotFound = errors.New("branch not found")
  36. // ErrTagExists an error stating the specified tag already exists
  37. ErrTagExists = errors.New("tag already exists")
  38. // ErrTagNotFound an error stating the specified tag does not exist
  39. ErrTagNotFound = errors.New("tag not found")
  40. // ErrFetching is returned when the packfile could not be downloaded
  41. ErrFetching = errors.New("unable to fetch packfile")
  42. ErrInvalidReference = errors.New("invalid reference, should be a tag or a branch")
  43. ErrRepositoryNotExists = errors.New("repository does not exist")
  44. ErrRepositoryAlreadyExists = errors.New("repository already exists")
  45. ErrRemoteNotFound = errors.New("remote not found")
  46. ErrRemoteExists = errors.New("remote already exists")
  47. ErrAnonymousRemoteName = errors.New("anonymous remote name must be 'anonymous'")
  48. ErrWorktreeNotProvided = errors.New("worktree should be provided")
  49. ErrIsBareRepository = errors.New("worktree not available in a bare repository")
  50. ErrUnableToResolveCommit = errors.New("unable to resolve commit")
  51. ErrPackedObjectsNotSupported = errors.New("Packed objects not supported")
  52. )
  53. // Repository represents a git repository
  54. type Repository struct {
  55. Storer storage.Storer
  56. r map[string]*Remote
  57. wt billy.Filesystem
  58. }
  59. // Init creates an empty git repository, based on the given Storer and worktree.
  60. // The worktree Filesystem is optional, if nil a bare repository is created. If
  61. // the given storer is not empty ErrRepositoryAlreadyExists is returned
  62. func Init(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
  63. if err := initStorer(s); err != nil {
  64. return nil, err
  65. }
  66. r := newRepository(s, worktree)
  67. _, err := r.Reference(plumbing.HEAD, false)
  68. switch err {
  69. case plumbing.ErrReferenceNotFound:
  70. case nil:
  71. return nil, ErrRepositoryAlreadyExists
  72. default:
  73. return nil, err
  74. }
  75. h := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.Master)
  76. if err := s.SetReference(h); err != nil {
  77. return nil, err
  78. }
  79. if worktree == nil {
  80. r.setIsBare(true)
  81. return r, nil
  82. }
  83. return r, setWorktreeAndStoragePaths(r, worktree)
  84. }
  85. func initStorer(s storer.Storer) error {
  86. i, ok := s.(storer.Initializer)
  87. if !ok {
  88. return nil
  89. }
  90. return i.Init()
  91. }
  92. func setWorktreeAndStoragePaths(r *Repository, worktree billy.Filesystem) error {
  93. type fsBased interface {
  94. Filesystem() billy.Filesystem
  95. }
  96. // .git file is only created if the storage is file based and the file
  97. // system is osfs.OS
  98. fs, isFSBased := r.Storer.(fsBased)
  99. if !isFSBased {
  100. return nil
  101. }
  102. if err := createDotGitFile(worktree, fs.Filesystem()); err != nil {
  103. return err
  104. }
  105. return setConfigWorktree(r, worktree, fs.Filesystem())
  106. }
  107. func createDotGitFile(worktree, storage billy.Filesystem) error {
  108. path, err := filepath.Rel(worktree.Root(), storage.Root())
  109. if err != nil {
  110. path = storage.Root()
  111. }
  112. if path == GitDirName {
  113. // not needed, since the folder is the default place
  114. return nil
  115. }
  116. f, err := worktree.Create(GitDirName)
  117. if err != nil {
  118. return err
  119. }
  120. defer f.Close()
  121. _, err = fmt.Fprintf(f, "gitdir: %s\n", path)
  122. return err
  123. }
  124. func setConfigWorktree(r *Repository, worktree, storage billy.Filesystem) error {
  125. path, err := filepath.Rel(storage.Root(), worktree.Root())
  126. if err != nil {
  127. path = worktree.Root()
  128. }
  129. if path == ".." {
  130. // not needed, since the folder is the default place
  131. return nil
  132. }
  133. cfg, err := r.Config()
  134. if err != nil {
  135. return err
  136. }
  137. cfg.Core.Worktree = path
  138. return r.Storer.SetConfig(cfg)
  139. }
  140. // Open opens a git repository using the given Storer and worktree filesystem,
  141. // if the given storer is complete empty ErrRepositoryNotExists is returned.
  142. // The worktree can be nil when the repository being opened is bare, if the
  143. // repository is a normal one (not bare) and worktree is nil the err
  144. // ErrWorktreeNotProvided is returned
  145. func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
  146. _, err := s.Reference(plumbing.HEAD)
  147. if err == plumbing.ErrReferenceNotFound {
  148. return nil, ErrRepositoryNotExists
  149. }
  150. if err != nil {
  151. return nil, err
  152. }
  153. return newRepository(s, worktree), nil
  154. }
  155. // Clone a repository into the given Storer and worktree Filesystem with the
  156. // given options, if worktree is nil a bare repository is created. If the given
  157. // storer is not empty ErrRepositoryAlreadyExists is returned.
  158. //
  159. // The provided Context must be non-nil. If the context expires before the
  160. // operation is complete, an error is returned. The context only affects to the
  161. // transport operations.
  162. func Clone(s storage.Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
  163. return CloneContext(context.Background(), s, worktree, o)
  164. }
  165. // CloneContext a repository into the given Storer and worktree Filesystem with
  166. // the given options, if worktree is nil a bare repository is created. If the
  167. // given storer is not empty ErrRepositoryAlreadyExists is returned.
  168. //
  169. // The provided Context must be non-nil. If the context expires before the
  170. // operation is complete, an error is returned. The context only affects to the
  171. // transport operations.
  172. func CloneContext(
  173. ctx context.Context, s storage.Storer, worktree billy.Filesystem, o *CloneOptions,
  174. ) (*Repository, error) {
  175. r, err := Init(s, worktree)
  176. if err != nil {
  177. return nil, err
  178. }
  179. return r, r.clone(ctx, o)
  180. }
  181. // PlainInit create an empty git repository at the given path. isBare defines
  182. // if the repository will have worktree (non-bare) or not (bare), if the path
  183. // is not empty ErrRepositoryAlreadyExists is returned.
  184. func PlainInit(path string, isBare bool) (*Repository, error) {
  185. var wt, dot billy.Filesystem
  186. if isBare {
  187. dot = osfs.New(path)
  188. } else {
  189. wt = osfs.New(path)
  190. dot, _ = wt.Chroot(GitDirName)
  191. }
  192. s := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
  193. return Init(s, wt)
  194. }
  195. // PlainOpen opens a git repository from the given path. It detects if the
  196. // repository is bare or a normal one. If the path doesn't contain a valid
  197. // repository ErrRepositoryNotExists is returned
  198. func PlainOpen(path string) (*Repository, error) {
  199. return PlainOpenWithOptions(path, &PlainOpenOptions{})
  200. }
  201. // PlainOpenWithOptions opens a git repository from the given path with specific
  202. // options. See PlainOpen for more info.
  203. func PlainOpenWithOptions(path string, o *PlainOpenOptions) (*Repository, error) {
  204. dot, wt, err := dotGitToOSFilesystems(path, o.DetectDotGit)
  205. if err != nil {
  206. return nil, err
  207. }
  208. if _, err := dot.Stat(""); err != nil {
  209. if os.IsNotExist(err) {
  210. return nil, ErrRepositoryNotExists
  211. }
  212. return nil, err
  213. }
  214. s := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
  215. return Open(s, wt)
  216. }
  217. func dotGitToOSFilesystems(path string, detect bool) (dot, wt billy.Filesystem, err error) {
  218. if path, err = filepath.Abs(path); err != nil {
  219. return nil, nil, err
  220. }
  221. var fs billy.Filesystem
  222. var fi os.FileInfo
  223. for {
  224. fs = osfs.New(path)
  225. fi, err = fs.Stat(GitDirName)
  226. if err == nil {
  227. // no error; stop
  228. break
  229. }
  230. if !os.IsNotExist(err) {
  231. // unknown error; stop
  232. return nil, nil, err
  233. }
  234. if detect {
  235. // try its parent as long as we haven't reached
  236. // the root dir
  237. if dir := filepath.Dir(path); dir != path {
  238. path = dir
  239. continue
  240. }
  241. }
  242. // not detecting via parent dirs and the dir does not exist;
  243. // stop
  244. return fs, nil, nil
  245. }
  246. if fi.IsDir() {
  247. dot, err = fs.Chroot(GitDirName)
  248. return dot, fs, err
  249. }
  250. dot, err = dotGitFileToOSFilesystem(path, fs)
  251. if err != nil {
  252. return nil, nil, err
  253. }
  254. return dot, fs, nil
  255. }
  256. func dotGitFileToOSFilesystem(path string, fs billy.Filesystem) (bfs billy.Filesystem, err error) {
  257. f, err := fs.Open(GitDirName)
  258. if err != nil {
  259. return nil, err
  260. }
  261. defer ioutil.CheckClose(f, &err)
  262. b, err := stdioutil.ReadAll(f)
  263. if err != nil {
  264. return nil, err
  265. }
  266. line := string(b)
  267. const prefix = "gitdir: "
  268. if !strings.HasPrefix(line, prefix) {
  269. return nil, fmt.Errorf(".git file has no %s prefix", prefix)
  270. }
  271. gitdir := strings.Split(line[len(prefix):], "\n")[0]
  272. gitdir = strings.TrimSpace(gitdir)
  273. if filepath.IsAbs(gitdir) {
  274. return osfs.New(gitdir), nil
  275. }
  276. return osfs.New(fs.Join(path, gitdir)), nil
  277. }
  278. // PlainClone a repository into the path with the given options, isBare defines
  279. // if the new repository will be bare or normal. If the path is not empty
  280. // ErrRepositoryAlreadyExists is returned.
  281. //
  282. // TODO(mcuadros): move isBare to CloneOptions in v5
  283. func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error) {
  284. return PlainCloneContext(context.Background(), path, isBare, o)
  285. }
  286. // PlainCloneContext a repository into the path with the given options, isBare
  287. // defines if the new repository will be bare or normal. If the path is not empty
  288. // ErrRepositoryAlreadyExists is returned.
  289. //
  290. // The provided Context must be non-nil. If the context expires before the
  291. // operation is complete, an error is returned. The context only affects to the
  292. // transport operations.
  293. //
  294. // TODO(mcuadros): move isBare to CloneOptions in v5
  295. // TODO(smola): refuse upfront to clone on a non-empty directory in v5, see #1027
  296. func PlainCloneContext(ctx context.Context, path string, isBare bool, o *CloneOptions) (*Repository, error) {
  297. cleanup, cleanupParent, err := checkIfCleanupIsNeeded(path)
  298. if err != nil {
  299. return nil, err
  300. }
  301. r, err := PlainInit(path, isBare)
  302. if err != nil {
  303. return nil, err
  304. }
  305. err = r.clone(ctx, o)
  306. if err != nil && err != ErrRepositoryAlreadyExists {
  307. if cleanup {
  308. cleanUpDir(path, cleanupParent)
  309. }
  310. }
  311. return r, err
  312. }
  313. func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
  314. return &Repository{
  315. Storer: s,
  316. wt: worktree,
  317. r: make(map[string]*Remote),
  318. }
  319. }
  320. func checkIfCleanupIsNeeded(path string) (cleanup bool, cleanParent bool, err error) {
  321. fi, err := os.Stat(path)
  322. if err != nil {
  323. if os.IsNotExist(err) {
  324. return true, true, nil
  325. }
  326. return false, false, err
  327. }
  328. if !fi.IsDir() {
  329. return false, false, fmt.Errorf("path is not a directory: %s", path)
  330. }
  331. f, err := os.Open(path)
  332. if err != nil {
  333. return false, false, err
  334. }
  335. defer ioutil.CheckClose(f, &err)
  336. _, err = f.Readdirnames(1)
  337. if err == io.EOF {
  338. return true, false, nil
  339. }
  340. if err != nil {
  341. return false, false, err
  342. }
  343. return false, false, nil
  344. }
  345. func cleanUpDir(path string, all bool) error {
  346. if all {
  347. return os.RemoveAll(path)
  348. }
  349. f, err := os.Open(path)
  350. if err != nil {
  351. return err
  352. }
  353. defer ioutil.CheckClose(f, &err)
  354. names, err := f.Readdirnames(-1)
  355. if err != nil {
  356. return err
  357. }
  358. for _, name := range names {
  359. if err := os.RemoveAll(filepath.Join(path, name)); err != nil {
  360. return err
  361. }
  362. }
  363. return err
  364. }
  365. // Config return the repository config. In a filesystem backed repository this
  366. // means read the `.git/config`.
  367. func (r *Repository) Config() (*config.Config, error) {
  368. return r.Storer.Config()
  369. }
  370. // SetConfig marshall and writes the repository config. In a filesystem backed
  371. // repository this means write the `.git/config`. This function should be called
  372. // with the result of `Repository.Config` and never with the output of
  373. // `Repository.ConfigScoped`.
  374. func (r *Repository) SetConfig(cfg *config.Config) error {
  375. return r.Storer.SetConfig(cfg)
  376. }
  377. // ConfigScoped returns the repository config, merged with requested scope and
  378. // lower. For example if, config.GlobalScope is given the local and global config
  379. // are returned merged in one config value.
  380. func (r *Repository) ConfigScoped(scope config.Scope) (*config.Config, error) {
  381. // TODO(mcuadros): v6, add this as ConfigOptions.Scoped
  382. var err error
  383. system := config.NewConfig()
  384. if scope >= config.SystemScope {
  385. system, err = config.LoadConfig(config.SystemScope)
  386. if err != nil {
  387. return nil, err
  388. }
  389. }
  390. global := config.NewConfig()
  391. if scope >= config.GlobalScope {
  392. global, err = config.LoadConfig(config.GlobalScope)
  393. if err != nil {
  394. return nil, err
  395. }
  396. }
  397. local, err := r.Storer.Config()
  398. if err != nil {
  399. return nil, err
  400. }
  401. _ = mergo.Merge(global, system)
  402. _ = mergo.Merge(local, global)
  403. return local, nil
  404. }
  405. // Remote return a remote if exists
  406. func (r *Repository) Remote(name string) (*Remote, error) {
  407. cfg, err := r.Config()
  408. if err != nil {
  409. return nil, err
  410. }
  411. c, ok := cfg.Remotes[name]
  412. if !ok {
  413. return nil, ErrRemoteNotFound
  414. }
  415. return NewRemote(r.Storer, c), nil
  416. }
  417. // Remotes returns a list with all the remotes
  418. func (r *Repository) Remotes() ([]*Remote, error) {
  419. cfg, err := r.Config()
  420. if err != nil {
  421. return nil, err
  422. }
  423. remotes := make([]*Remote, len(cfg.Remotes))
  424. var i int
  425. for _, c := range cfg.Remotes {
  426. remotes[i] = NewRemote(r.Storer, c)
  427. i++
  428. }
  429. return remotes, nil
  430. }
  431. // CreateRemote creates a new remote
  432. func (r *Repository) CreateRemote(c *config.RemoteConfig) (*Remote, error) {
  433. if err := c.Validate(); err != nil {
  434. return nil, err
  435. }
  436. remote := NewRemote(r.Storer, c)
  437. cfg, err := r.Config()
  438. if err != nil {
  439. return nil, err
  440. }
  441. if _, ok := cfg.Remotes[c.Name]; ok {
  442. return nil, ErrRemoteExists
  443. }
  444. cfg.Remotes[c.Name] = c
  445. return remote, r.Storer.SetConfig(cfg)
  446. }
  447. // CreateRemoteAnonymous creates a new anonymous remote. c.Name must be "anonymous".
  448. // It's used like 'git fetch git@github.com:src-d/go-git.git master:master'.
  449. func (r *Repository) CreateRemoteAnonymous(c *config.RemoteConfig) (*Remote, error) {
  450. if err := c.Validate(); err != nil {
  451. return nil, err
  452. }
  453. if c.Name != "anonymous" {
  454. return nil, ErrAnonymousRemoteName
  455. }
  456. remote := NewRemote(r.Storer, c)
  457. return remote, nil
  458. }
  459. // DeleteRemote delete a remote from the repository and delete the config
  460. func (r *Repository) DeleteRemote(name string) error {
  461. cfg, err := r.Config()
  462. if err != nil {
  463. return err
  464. }
  465. if _, ok := cfg.Remotes[name]; !ok {
  466. return ErrRemoteNotFound
  467. }
  468. delete(cfg.Remotes, name)
  469. return r.Storer.SetConfig(cfg)
  470. }
  471. // Branch return a Branch if exists
  472. func (r *Repository) Branch(name string) (*config.Branch, error) {
  473. cfg, err := r.Config()
  474. if err != nil {
  475. return nil, err
  476. }
  477. b, ok := cfg.Branches[name]
  478. if !ok {
  479. return nil, ErrBranchNotFound
  480. }
  481. return b, nil
  482. }
  483. // CreateBranch creates a new Branch
  484. func (r *Repository) CreateBranch(c *config.Branch) error {
  485. if err := c.Validate(); err != nil {
  486. return err
  487. }
  488. cfg, err := r.Config()
  489. if err != nil {
  490. return err
  491. }
  492. if _, ok := cfg.Branches[c.Name]; ok {
  493. return ErrBranchExists
  494. }
  495. cfg.Branches[c.Name] = c
  496. return r.Storer.SetConfig(cfg)
  497. }
  498. // DeleteBranch delete a Branch from the repository and delete the config
  499. func (r *Repository) DeleteBranch(name string) error {
  500. cfg, err := r.Config()
  501. if err != nil {
  502. return err
  503. }
  504. if _, ok := cfg.Branches[name]; !ok {
  505. return ErrBranchNotFound
  506. }
  507. delete(cfg.Branches, name)
  508. return r.Storer.SetConfig(cfg)
  509. }
  510. // CreateTag creates a tag. If opts is included, the tag is an annotated tag,
  511. // otherwise a lightweight tag is created.
  512. func (r *Repository) CreateTag(name string, hash plumbing.Hash, opts *CreateTagOptions) (*plumbing.Reference, error) {
  513. rname := plumbing.ReferenceName(path.Join("refs", "tags", name))
  514. _, err := r.Storer.Reference(rname)
  515. switch err {
  516. case nil:
  517. // Tag exists, this is an error
  518. return nil, ErrTagExists
  519. case plumbing.ErrReferenceNotFound:
  520. // Tag missing, available for creation, pass this
  521. default:
  522. // Some other error
  523. return nil, err
  524. }
  525. var target plumbing.Hash
  526. if opts != nil {
  527. target, err = r.createTagObject(name, hash, opts)
  528. if err != nil {
  529. return nil, err
  530. }
  531. } else {
  532. target = hash
  533. }
  534. ref := plumbing.NewHashReference(rname, target)
  535. if err = r.Storer.SetReference(ref); err != nil {
  536. return nil, err
  537. }
  538. return ref, nil
  539. }
  540. func (r *Repository) createTagObject(name string, hash plumbing.Hash, opts *CreateTagOptions) (plumbing.Hash, error) {
  541. if err := opts.Validate(r, hash); err != nil {
  542. return plumbing.ZeroHash, err
  543. }
  544. rawobj, err := object.GetObject(r.Storer, hash)
  545. if err != nil {
  546. return plumbing.ZeroHash, err
  547. }
  548. tag := &object.Tag{
  549. Name: name,
  550. Tagger: *opts.Tagger,
  551. Message: opts.Message,
  552. TargetType: rawobj.Type(),
  553. Target: hash,
  554. }
  555. if opts.SignKey != nil {
  556. sig, err := r.buildTagSignature(tag, opts.SignKey)
  557. if err != nil {
  558. return plumbing.ZeroHash, err
  559. }
  560. tag.PGPSignature = sig
  561. }
  562. obj := r.Storer.NewEncodedObject()
  563. if err := tag.Encode(obj); err != nil {
  564. return plumbing.ZeroHash, err
  565. }
  566. return r.Storer.SetEncodedObject(obj)
  567. }
  568. func (r *Repository) buildTagSignature(tag *object.Tag, signKey *openpgp.Entity) (string, error) {
  569. encoded := &plumbing.MemoryObject{}
  570. if err := tag.Encode(encoded); err != nil {
  571. return "", err
  572. }
  573. rdr, err := encoded.Reader()
  574. if err != nil {
  575. return "", err
  576. }
  577. var b bytes.Buffer
  578. if err := openpgp.ArmoredDetachSign(&b, signKey, rdr, nil); err != nil {
  579. return "", err
  580. }
  581. return b.String(), nil
  582. }
  583. // Tag returns a tag from the repository.
  584. //
  585. // If you want to check to see if the tag is an annotated tag, you can call
  586. // TagObject on the hash of the reference in ForEach:
  587. //
  588. // ref, err := r.Tag("v0.1.0")
  589. // if err != nil {
  590. // // Handle error
  591. // }
  592. //
  593. // obj, err := r.TagObject(ref.Hash())
  594. // switch err {
  595. // case nil:
  596. // // Tag object present
  597. // case plumbing.ErrObjectNotFound:
  598. // // Not a tag object
  599. // default:
  600. // // Some other error
  601. // }
  602. //
  603. func (r *Repository) Tag(name string) (*plumbing.Reference, error) {
  604. ref, err := r.Reference(plumbing.ReferenceName(path.Join("refs", "tags", name)), false)
  605. if err != nil {
  606. if err == plumbing.ErrReferenceNotFound {
  607. // Return a friendly error for this one, versus just ReferenceNotFound.
  608. return nil, ErrTagNotFound
  609. }
  610. return nil, err
  611. }
  612. return ref, nil
  613. }
  614. // DeleteTag deletes a tag from the repository.
  615. func (r *Repository) DeleteTag(name string) error {
  616. _, err := r.Tag(name)
  617. if err != nil {
  618. return err
  619. }
  620. return r.Storer.RemoveReference(plumbing.ReferenceName(path.Join("refs", "tags", name)))
  621. }
  622. func (r *Repository) resolveToCommitHash(h plumbing.Hash) (plumbing.Hash, error) {
  623. obj, err := r.Storer.EncodedObject(plumbing.AnyObject, h)
  624. if err != nil {
  625. return plumbing.ZeroHash, err
  626. }
  627. switch obj.Type() {
  628. case plumbing.TagObject:
  629. t, err := object.DecodeTag(r.Storer, obj)
  630. if err != nil {
  631. return plumbing.ZeroHash, err
  632. }
  633. return r.resolveToCommitHash(t.Target)
  634. case plumbing.CommitObject:
  635. return h, nil
  636. default:
  637. return plumbing.ZeroHash, ErrUnableToResolveCommit
  638. }
  639. }
  640. // Clone clones a remote repository
  641. func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
  642. if err := o.Validate(); err != nil {
  643. return err
  644. }
  645. c := &config.RemoteConfig{
  646. Name: o.RemoteName,
  647. URLs: []string{o.URL},
  648. Fetch: r.cloneRefSpec(o),
  649. }
  650. if _, err := r.CreateRemote(c); err != nil {
  651. return err
  652. }
  653. ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
  654. RefSpecs: c.Fetch,
  655. Depth: o.Depth,
  656. Auth: o.Auth,
  657. Progress: o.Progress,
  658. Tags: o.Tags,
  659. RemoteName: o.RemoteName,
  660. }, o.ReferenceName)
  661. if err != nil {
  662. return err
  663. }
  664. if r.wt != nil && !o.NoCheckout {
  665. w, err := r.Worktree()
  666. if err != nil {
  667. return err
  668. }
  669. head, err := r.Head()
  670. if err != nil {
  671. return err
  672. }
  673. if err := w.Reset(&ResetOptions{
  674. Mode: MergeReset,
  675. Commit: head.Hash(),
  676. }); err != nil {
  677. return err
  678. }
  679. if o.RecurseSubmodules != NoRecurseSubmodules {
  680. if err := w.updateSubmodules(&SubmoduleUpdateOptions{
  681. RecurseSubmodules: o.RecurseSubmodules,
  682. Auth: o.Auth,
  683. }); err != nil {
  684. return err
  685. }
  686. }
  687. }
  688. if err := r.updateRemoteConfigIfNeeded(o, c, ref); err != nil {
  689. return err
  690. }
  691. if ref.Name().IsBranch() {
  692. branchRef := ref.Name()
  693. branchName := strings.Split(string(branchRef), "refs/heads/")[1]
  694. b := &config.Branch{
  695. Name: branchName,
  696. Merge: branchRef,
  697. }
  698. if o.RemoteName == "" {
  699. b.Remote = "origin"
  700. } else {
  701. b.Remote = o.RemoteName
  702. }
  703. if err := r.CreateBranch(b); err != nil {
  704. return err
  705. }
  706. }
  707. return nil
  708. }
  709. const (
  710. refspecTag = "+refs/tags/%s:refs/tags/%[1]s"
  711. refspecSingleBranch = "+refs/heads/%s:refs/remotes/%s/%[1]s"
  712. refspecSingleBranchHEAD = "+HEAD:refs/remotes/%s/HEAD"
  713. )
  714. func (r *Repository) cloneRefSpec(o *CloneOptions) []config.RefSpec {
  715. switch {
  716. case o.ReferenceName.IsTag():
  717. return []config.RefSpec{
  718. config.RefSpec(fmt.Sprintf(refspecTag, o.ReferenceName.Short())),
  719. }
  720. case o.SingleBranch && o.ReferenceName == plumbing.HEAD:
  721. return []config.RefSpec{
  722. config.RefSpec(fmt.Sprintf(refspecSingleBranchHEAD, o.RemoteName)),
  723. config.RefSpec(fmt.Sprintf(refspecSingleBranch, plumbing.Master.Short(), o.RemoteName)),
  724. }
  725. case o.SingleBranch:
  726. return []config.RefSpec{
  727. config.RefSpec(fmt.Sprintf(refspecSingleBranch, o.ReferenceName.Short(), o.RemoteName)),
  728. }
  729. default:
  730. return []config.RefSpec{
  731. config.RefSpec(fmt.Sprintf(config.DefaultFetchRefSpec, o.RemoteName)),
  732. }
  733. }
  734. }
  735. func (r *Repository) setIsBare(isBare bool) error {
  736. cfg, err := r.Config()
  737. if err != nil {
  738. return err
  739. }
  740. cfg.Core.IsBare = isBare
  741. return r.Storer.SetConfig(cfg)
  742. }
  743. func (r *Repository) updateRemoteConfigIfNeeded(o *CloneOptions, c *config.RemoteConfig, head *plumbing.Reference) error {
  744. if !o.SingleBranch {
  745. return nil
  746. }
  747. c.Fetch = r.cloneRefSpec(o)
  748. cfg, err := r.Config()
  749. if err != nil {
  750. return err
  751. }
  752. cfg.Remotes[c.Name] = c
  753. return r.Storer.SetConfig(cfg)
  754. }
  755. func (r *Repository) fetchAndUpdateReferences(
  756. ctx context.Context, o *FetchOptions, ref plumbing.ReferenceName,
  757. ) (*plumbing.Reference, error) {
  758. if err := o.Validate(); err != nil {
  759. return nil, err
  760. }
  761. remote, err := r.Remote(o.RemoteName)
  762. if err != nil {
  763. return nil, err
  764. }
  765. objsUpdated := true
  766. remoteRefs, err := remote.fetch(ctx, o)
  767. if err == NoErrAlreadyUpToDate {
  768. objsUpdated = false
  769. } else if err == packfile.ErrEmptyPackfile {
  770. return nil, ErrFetching
  771. } else if err != nil {
  772. return nil, err
  773. }
  774. resolvedRef, err := storer.ResolveReference(remoteRefs, ref)
  775. if err != nil {
  776. return nil, err
  777. }
  778. refsUpdated, err := r.updateReferences(remote.c.Fetch, resolvedRef)
  779. if err != nil {
  780. return nil, err
  781. }
  782. if !objsUpdated && !refsUpdated {
  783. return nil, NoErrAlreadyUpToDate
  784. }
  785. return resolvedRef, nil
  786. }
  787. func (r *Repository) updateReferences(spec []config.RefSpec,
  788. resolvedRef *plumbing.Reference) (updated bool, err error) {
  789. if !resolvedRef.Name().IsBranch() {
  790. // Detached HEAD mode
  791. h, err := r.resolveToCommitHash(resolvedRef.Hash())
  792. if err != nil {
  793. return false, err
  794. }
  795. head := plumbing.NewHashReference(plumbing.HEAD, h)
  796. return updateReferenceStorerIfNeeded(r.Storer, head)
  797. }
  798. refs := []*plumbing.Reference{
  799. // Create local reference for the resolved ref
  800. resolvedRef,
  801. // Create local symbolic HEAD
  802. plumbing.NewSymbolicReference(plumbing.HEAD, resolvedRef.Name()),
  803. }
  804. refs = append(refs, r.calculateRemoteHeadReference(spec, resolvedRef)...)
  805. for _, ref := range refs {
  806. u, err := updateReferenceStorerIfNeeded(r.Storer, ref)
  807. if err != nil {
  808. return updated, err
  809. }
  810. if u {
  811. updated = true
  812. }
  813. }
  814. return
  815. }
  816. func (r *Repository) calculateRemoteHeadReference(spec []config.RefSpec,
  817. resolvedHead *plumbing.Reference) []*plumbing.Reference {
  818. var refs []*plumbing.Reference
  819. // Create resolved HEAD reference with remote prefix if it does not
  820. // exist. This is needed when using single branch and HEAD.
  821. for _, rs := range spec {
  822. name := resolvedHead.Name()
  823. if !rs.Match(name) {
  824. continue
  825. }
  826. name = rs.Dst(name)
  827. _, err := r.Storer.Reference(name)
  828. if err == plumbing.ErrReferenceNotFound {
  829. refs = append(refs, plumbing.NewHashReference(name, resolvedHead.Hash()))
  830. }
  831. }
  832. return refs
  833. }
  834. func checkAndUpdateReferenceStorerIfNeeded(
  835. s storer.ReferenceStorer, r, old *plumbing.Reference) (
  836. updated bool, err error) {
  837. p, err := s.Reference(r.Name())
  838. if err != nil && err != plumbing.ErrReferenceNotFound {
  839. return false, err
  840. }
  841. // we use the string method to compare references, is the easiest way
  842. if err == plumbing.ErrReferenceNotFound || r.String() != p.String() {
  843. if err := s.CheckAndSetReference(r, old); err != nil {
  844. return false, err
  845. }
  846. return true, nil
  847. }
  848. return false, nil
  849. }
  850. func updateReferenceStorerIfNeeded(
  851. s storer.ReferenceStorer, r *plumbing.Reference) (updated bool, err error) {
  852. return checkAndUpdateReferenceStorerIfNeeded(s, r, nil)
  853. }
  854. // Fetch fetches references along with the objects necessary to complete
  855. // their histories, from the remote named as FetchOptions.RemoteName.
  856. //
  857. // Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
  858. // no changes to be fetched, or an error.
  859. func (r *Repository) Fetch(o *FetchOptions) error {
  860. return r.FetchContext(context.Background(), o)
  861. }
  862. // FetchContext fetches references along with the objects necessary to complete
  863. // their histories, from the remote named as FetchOptions.RemoteName.
  864. //
  865. // Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
  866. // no changes to be fetched, or an error.
  867. //
  868. // The provided Context must be non-nil. If the context expires before the
  869. // operation is complete, an error is returned. The context only affects to the
  870. // transport operations.
  871. func (r *Repository) FetchContext(ctx context.Context, o *FetchOptions) error {
  872. if err := o.Validate(); err != nil {
  873. return err
  874. }
  875. remote, err := r.Remote(o.RemoteName)
  876. if err != nil {
  877. return err
  878. }
  879. return remote.FetchContext(ctx, o)
  880. }
  881. // Push performs a push to the remote. Returns NoErrAlreadyUpToDate if
  882. // the remote was already up-to-date, from the remote named as
  883. // FetchOptions.RemoteName.
  884. func (r *Repository) Push(o *PushOptions) error {
  885. return r.PushContext(context.Background(), o)
  886. }
  887. // PushContext performs a push to the remote. Returns NoErrAlreadyUpToDate if
  888. // the remote was already up-to-date, from the remote named as
  889. // FetchOptions.RemoteName.
  890. //
  891. // The provided Context must be non-nil. If the context expires before the
  892. // operation is complete, an error is returned. The context only affects to the
  893. // transport operations.
  894. func (r *Repository) PushContext(ctx context.Context, o *PushOptions) error {
  895. if err := o.Validate(); err != nil {
  896. return err
  897. }
  898. remote, err := r.Remote(o.RemoteName)
  899. if err != nil {
  900. return err
  901. }
  902. return remote.PushContext(ctx, o)
  903. }
  904. // Log returns the commit history from the given LogOptions.
  905. func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) {
  906. fn := commitIterFunc(o.Order)
  907. if fn == nil {
  908. return nil, fmt.Errorf("invalid Order=%v", o.Order)
  909. }
  910. var (
  911. it object.CommitIter
  912. err error
  913. )
  914. if o.All {
  915. it, err = r.logAll(fn)
  916. } else {
  917. it, err = r.log(o.From, fn)
  918. }
  919. if err != nil {
  920. return nil, err
  921. }
  922. if o.FileName != nil {
  923. // for `git log --all` also check parent (if the next commit comes from the real parent)
  924. it = r.logWithFile(*o.FileName, it, o.All)
  925. }
  926. if o.PathFilter != nil {
  927. it = r.logWithPathFilter(o.PathFilter, it, o.All)
  928. }
  929. if o.Since != nil || o.Until != nil {
  930. limitOptions := object.LogLimitOptions{Since: o.Since, Until: o.Until}
  931. it = r.logWithLimit(it, limitOptions)
  932. }
  933. return it, nil
  934. }
  935. func (r *Repository) log(from plumbing.Hash, commitIterFunc func(*object.Commit) object.CommitIter) (object.CommitIter, error) {
  936. h := from
  937. if from == plumbing.ZeroHash {
  938. head, err := r.Head()
  939. if err != nil {
  940. return nil, err
  941. }
  942. h = head.Hash()
  943. }
  944. commit, err := r.CommitObject(h)
  945. if err != nil {
  946. return nil, err
  947. }
  948. return commitIterFunc(commit), nil
  949. }
  950. func (r *Repository) logAll(commitIterFunc func(*object.Commit) object.CommitIter) (object.CommitIter, error) {
  951. return object.NewCommitAllIter(r.Storer, commitIterFunc)
  952. }
  953. func (*Repository) logWithFile(fileName string, commitIter object.CommitIter, checkParent bool) object.CommitIter {
  954. return object.NewCommitPathIterFromIter(
  955. func(path string) bool {
  956. return path == fileName
  957. },
  958. commitIter,
  959. checkParent,
  960. )
  961. }
  962. func (*Repository) logWithPathFilter(pathFilter func(string) bool, commitIter object.CommitIter, checkParent bool) object.CommitIter {
  963. return object.NewCommitPathIterFromIter(
  964. pathFilter,
  965. commitIter,
  966. checkParent,
  967. )
  968. }
  969. func (*Repository) logWithLimit(commitIter object.CommitIter, limitOptions object.LogLimitOptions) object.CommitIter {
  970. return object.NewCommitLimitIterFromIter(commitIter, limitOptions)
  971. }
  972. func commitIterFunc(order LogOrder) func(c *object.Commit) object.CommitIter {
  973. switch order {
  974. case LogOrderDefault:
  975. return func(c *object.Commit) object.CommitIter {
  976. return object.NewCommitPreorderIter(c, nil, nil)
  977. }
  978. case LogOrderDFS:
  979. return func(c *object.Commit) object.CommitIter {
  980. return object.NewCommitPreorderIter(c, nil, nil)
  981. }
  982. case LogOrderDFSPost:
  983. return func(c *object.Commit) object.CommitIter {
  984. return object.NewCommitPostorderIter(c, nil)
  985. }
  986. case LogOrderBSF:
  987. return func(c *object.Commit) object.CommitIter {
  988. return object.NewCommitIterBSF(c, nil, nil)
  989. }
  990. case LogOrderCommitterTime:
  991. return func(c *object.Commit) object.CommitIter {
  992. return object.NewCommitIterCTime(c, nil, nil)
  993. }
  994. }
  995. return nil
  996. }
  997. // Tags returns all the tag References in a repository.
  998. //
  999. // If you want to check to see if the tag is an annotated tag, you can call
  1000. // TagObject on the hash Reference passed in through ForEach:
  1001. //
  1002. // iter, err := r.Tags()
  1003. // if err != nil {
  1004. // // Handle error
  1005. // }
  1006. //
  1007. // if err := iter.ForEach(func (ref *plumbing.Reference) error {
  1008. // obj, err := r.TagObject(ref.Hash())
  1009. // switch err {
  1010. // case nil:
  1011. // // Tag object present
  1012. // case plumbing.ErrObjectNotFound:
  1013. // // Not a tag object
  1014. // default:
  1015. // // Some other error
  1016. // return err
  1017. // }
  1018. // }); err != nil {
  1019. // // Handle outer iterator error
  1020. // }
  1021. //
  1022. func (r *Repository) Tags() (storer.ReferenceIter, error) {
  1023. refIter, err := r.Storer.IterReferences()
  1024. if err != nil {
  1025. return nil, err
  1026. }
  1027. return storer.NewReferenceFilteredIter(
  1028. func(r *plumbing.Reference) bool {
  1029. return r.Name().IsTag()
  1030. }, refIter), nil
  1031. }
  1032. // Branches returns all the References that are Branches.
  1033. func (r *Repository) Branches() (storer.ReferenceIter, error) {
  1034. refIter, err := r.Storer.IterReferences()
  1035. if err != nil {
  1036. return nil, err
  1037. }
  1038. return storer.NewReferenceFilteredIter(
  1039. func(r *plumbing.Reference) bool {
  1040. return r.Name().IsBranch()
  1041. }, refIter), nil
  1042. }
  1043. // Notes returns all the References that are notes. For more information:
  1044. // https://git-scm.com/docs/git-notes
  1045. func (r *Repository) Notes() (storer.ReferenceIter, error) {
  1046. refIter, err := r.Storer.IterReferences()
  1047. if err != nil {
  1048. return nil, err
  1049. }
  1050. return storer.NewReferenceFilteredIter(
  1051. func(r *plumbing.Reference) bool {
  1052. return r.Name().IsNote()
  1053. }, refIter), nil
  1054. }
  1055. // TreeObject return a Tree with the given hash. If not found
  1056. // plumbing.ErrObjectNotFound is returned
  1057. func (r *Repository) TreeObject(h plumbing.Hash) (*object.Tree, error) {
  1058. return object.GetTree(r.Storer, h)
  1059. }
  1060. // TreeObjects returns an unsorted TreeIter with all the trees in the repository
  1061. func (r *Repository) TreeObjects() (*object.TreeIter, error) {
  1062. iter, err := r.Storer.IterEncodedObjects(plumbing.TreeObject)
  1063. if err != nil {
  1064. return nil, err
  1065. }
  1066. return object.NewTreeIter(r.Storer, iter), nil
  1067. }
  1068. // CommitObject return a Commit with the given hash. If not found
  1069. // plumbing.ErrObjectNotFound is returned.
  1070. func (r *Repository) CommitObject(h plumbing.Hash) (*object.Commit, error) {
  1071. return object.GetCommit(r.Storer, h)
  1072. }
  1073. // CommitObjects returns an unsorted CommitIter with all the commits in the repository.
  1074. func (r *Repository) CommitObjects() (object.CommitIter, error) {
  1075. iter, err := r.Storer.IterEncodedObjects(plumbing.CommitObject)
  1076. if err != nil {
  1077. return nil, err
  1078. }
  1079. return object.NewCommitIter(r.Storer, iter), nil
  1080. }
  1081. // BlobObject returns a Blob with the given hash. If not found
  1082. // plumbing.ErrObjectNotFound is returned.
  1083. func (r *Repository) BlobObject(h plumbing.Hash) (*object.Blob, error) {
  1084. return object.GetBlob(r.Storer, h)
  1085. }
  1086. // BlobObjects returns an unsorted BlobIter with all the blobs in the repository.
  1087. func (r *Repository) BlobObjects() (*object.BlobIter, error) {
  1088. iter, err := r.Storer.IterEncodedObjects(plumbing.BlobObject)
  1089. if err != nil {
  1090. return nil, err
  1091. }
  1092. return object.NewBlobIter(r.Storer, iter), nil
  1093. }
  1094. // TagObject returns a Tag with the given hash. If not found
  1095. // plumbing.ErrObjectNotFound is returned. This method only returns
  1096. // annotated Tags, no lightweight Tags.
  1097. func (r *Repository) TagObject(h plumbing.Hash) (*object.Tag, error) {
  1098. return object.GetTag(r.Storer, h)
  1099. }
  1100. // TagObjects returns a unsorted TagIter that can step through all of the annotated
  1101. // tags in the repository.
  1102. func (r *Repository) TagObjects() (*object.TagIter, error) {
  1103. iter, err := r.Storer.IterEncodedObjects(plumbing.TagObject)
  1104. if err != nil {
  1105. return nil, err
  1106. }
  1107. return object.NewTagIter(r.Storer, iter), nil
  1108. }
  1109. // Object returns an Object with the given hash. If not found
  1110. // plumbing.ErrObjectNotFound is returned.
  1111. func (r *Repository) Object(t plumbing.ObjectType, h plumbing.Hash) (object.Object, error) {
  1112. obj, err := r.Storer.EncodedObject(t, h)
  1113. if err != nil {
  1114. return nil, err
  1115. }
  1116. return object.DecodeObject(r.Storer, obj)
  1117. }
  1118. // Objects returns an unsorted ObjectIter with all the objects in the repository.
  1119. func (r *Repository) Objects() (*object.ObjectIter, error) {
  1120. iter, err := r.Storer.IterEncodedObjects(plumbing.AnyObject)
  1121. if err != nil {
  1122. return nil, err
  1123. }
  1124. return object.NewObjectIter(r.Storer, iter), nil
  1125. }
  1126. // Head returns the reference where HEAD is pointing to.
  1127. func (r *Repository) Head() (*plumbing.Reference, error) {
  1128. return storer.ResolveReference(r.Storer, plumbing.HEAD)
  1129. }
  1130. // Reference returns the reference for a given reference name. If resolved is
  1131. // true, any symbolic reference will be resolved.
  1132. func (r *Repository) Reference(name plumbing.ReferenceName, resolved bool) (
  1133. *plumbing.Reference, error) {
  1134. if resolved {
  1135. return storer.ResolveReference(r.Storer, name)
  1136. }
  1137. return r.Storer.Reference(name)
  1138. }
  1139. // References returns an unsorted ReferenceIter for all references.
  1140. func (r *Repository) References() (storer.ReferenceIter, error) {
  1141. return r.Storer.IterReferences()
  1142. }
  1143. // Worktree returns a worktree based on the given fs, if nil the default
  1144. // worktree will be used.
  1145. func (r *Repository) Worktree() (*Worktree, error) {
  1146. if r.wt == nil {
  1147. return nil, ErrIsBareRepository
  1148. }
  1149. return &Worktree{r: r, Filesystem: r.wt}, nil
  1150. }
  1151. // ResolveRevision resolves revision to corresponding hash. It will always
  1152. // resolve to a commit hash, not a tree or annotated tag.
  1153. //
  1154. // Implemented resolvers : HEAD, branch, tag, heads/branch, refs/heads/branch,
  1155. // refs/tags/tag, refs/remotes/origin/branch, refs/remotes/origin/HEAD, tilde and caret (HEAD~1, master~^, tag~2, ref/heads/master~1, ...), selection by text (HEAD^{/fix nasty bug})
  1156. func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error) {
  1157. p := revision.NewParserFromString(string(rev))
  1158. items, err := p.Parse()
  1159. if err != nil {
  1160. return nil, err
  1161. }
  1162. var commit *object.Commit
  1163. for _, item := range items {
  1164. switch item.(type) {
  1165. case revision.Ref:
  1166. revisionRef := item.(revision.Ref)
  1167. var tryHashes []plumbing.Hash
  1168. maybeHash := plumbing.NewHash(string(revisionRef))
  1169. if !maybeHash.IsZero() {
  1170. tryHashes = append(tryHashes, maybeHash)
  1171. }
  1172. for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
  1173. ref, err := storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
  1174. if err == nil {
  1175. tryHashes = append(tryHashes, ref.Hash())
  1176. break
  1177. }
  1178. }
  1179. // in ambiguous cases, `git rev-parse` will emit a warning, but
  1180. // will always return the oid in preference to a ref; we don't have
  1181. // the ability to emit a warning here, so (for speed purposes)
  1182. // don't bother to detect the ambiguity either, just return in the
  1183. // priority that git would.
  1184. gotOne := false
  1185. for _, hash := range tryHashes {
  1186. commitObj, err := r.CommitObject(hash)
  1187. if err == nil {
  1188. commit = commitObj
  1189. gotOne = true
  1190. break
  1191. }
  1192. tagObj, err := r.TagObject(hash)
  1193. if err == nil {
  1194. // If the tag target lookup fails here, this most likely
  1195. // represents some sort of repo corruption, so let the
  1196. // error bubble up.
  1197. tagCommit, err := tagObj.Commit()
  1198. if err != nil {
  1199. return &plumbing.ZeroHash, err
  1200. }
  1201. commit = tagCommit
  1202. gotOne = true
  1203. break
  1204. }
  1205. }
  1206. if !gotOne {
  1207. return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
  1208. }
  1209. case revision.CaretPath:
  1210. depth := item.(revision.CaretPath).Depth
  1211. if depth == 0 {
  1212. break
  1213. }
  1214. iter := commit.Parents()
  1215. c, err := iter.Next()
  1216. if err != nil {
  1217. return &plumbing.ZeroHash, err
  1218. }
  1219. if depth == 1 {
  1220. commit = c
  1221. break
  1222. }
  1223. c, err = iter.Next()
  1224. if err != nil {
  1225. return &plumbing.ZeroHash, err
  1226. }
  1227. commit = c
  1228. case revision.TildePath:
  1229. for i := 0; i < item.(revision.TildePath).Depth; i++ {
  1230. c, err := commit.Parents().Next()
  1231. if err != nil {
  1232. return &plumbing.ZeroHash, err
  1233. }
  1234. commit = c
  1235. }
  1236. case revision.CaretReg:
  1237. history := object.NewCommitPreorderIter(commit, nil, nil)
  1238. re := item.(revision.CaretReg).Regexp
  1239. negate := item.(revision.CaretReg).Negate
  1240. var c *object.Commit
  1241. err := history.ForEach(func(hc *object.Commit) error {
  1242. if !negate && re.MatchString(hc.Message) {
  1243. c = hc
  1244. return storer.ErrStop
  1245. }
  1246. if negate && !re.MatchString(hc.Message) {
  1247. c = hc
  1248. return storer.ErrStop
  1249. }
  1250. return nil
  1251. })
  1252. if err != nil {
  1253. return &plumbing.ZeroHash, err
  1254. }
  1255. if c == nil {
  1256. return &plumbing.ZeroHash, fmt.Errorf(`No commit message match regexp : "%s"`, re.String())
  1257. }
  1258. commit = c
  1259. }
  1260. }
  1261. return &commit.Hash, nil
  1262. }
  1263. type RepackConfig struct {
  1264. // UseRefDeltas configures whether packfile encoder will use reference deltas.
  1265. // By default OFSDeltaObject is used.
  1266. UseRefDeltas bool
  1267. // OnlyDeletePacksOlderThan if set to non-zero value
  1268. // selects only objects older than the time provided.
  1269. OnlyDeletePacksOlderThan time.Time
  1270. }
  1271. func (r *Repository) RepackObjects(cfg *RepackConfig) (err error) {
  1272. pos, ok := r.Storer.(storer.PackedObjectStorer)
  1273. if !ok {
  1274. return ErrPackedObjectsNotSupported
  1275. }
  1276. // Get the existing object packs.
  1277. hs, err := pos.ObjectPacks()
  1278. if err != nil {
  1279. return err
  1280. }
  1281. // Create a new pack.
  1282. nh, err := r.createNewObjectPack(cfg)
  1283. if err != nil {
  1284. return err
  1285. }
  1286. // Delete old packs.
  1287. for _, h := range hs {
  1288. // Skip if new hash is the same as an old one.
  1289. if h == nh {
  1290. continue
  1291. }
  1292. err = pos.DeleteOldObjectPackAndIndex(h, cfg.OnlyDeletePacksOlderThan)
  1293. if err != nil {
  1294. return err
  1295. }
  1296. }
  1297. return nil
  1298. }
  1299. // createNewObjectPack is a helper for RepackObjects taking care
  1300. // of creating a new pack. It is used so the the PackfileWriter
  1301. // deferred close has the right scope.
  1302. func (r *Repository) createNewObjectPack(cfg *RepackConfig) (h plumbing.Hash, err error) {
  1303. ow := newObjectWalker(r.Storer)
  1304. err = ow.walkAllRefs()
  1305. if err != nil {
  1306. return h, err
  1307. }
  1308. objs := make([]plumbing.Hash, 0, len(ow.seen))
  1309. for h := range ow.seen {
  1310. objs = append(objs, h)
  1311. }
  1312. pfw, ok := r.Storer.(storer.PackfileWriter)
  1313. if !ok {
  1314. return h, fmt.Errorf("Repository storer is not a storer.PackfileWriter")
  1315. }
  1316. wc, err := pfw.PackfileWriter()
  1317. if err != nil {
  1318. return h, err
  1319. }
  1320. defer ioutil.CheckClose(wc, &err)
  1321. scfg, err := r.Config()
  1322. if err != nil {
  1323. return h, err
  1324. }
  1325. enc := packfile.NewEncoder(wc, r.Storer, cfg.UseRefDeltas)
  1326. h, err = enc.Encode(objs, scfg.Pack.Window)
  1327. if err != nil {
  1328. return h, err
  1329. }
  1330. // Delete the packed, loose objects.
  1331. if los, ok := r.Storer.(storer.LooseObjectStorer); ok {
  1332. err = los.ForEachObjectHash(func(hash plumbing.Hash) error {
  1333. if ow.isSeen(hash) {
  1334. err = los.DeleteLooseObject(hash)
  1335. if err != nil {
  1336. return err
  1337. }
  1338. }
  1339. return nil
  1340. })
  1341. if err != nil {
  1342. return h, err
  1343. }
  1344. }
  1345. return h, err
  1346. }