refs.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. # refs.py -- For dealing with git refs
  2. # Copyright (C) 2008-2013 Jelmer Vernooij <jelmer@samba.org>
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; version 2
  7. # of the License or (at your option) any later version of
  8. # the License.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  18. # MA 02110-1301, USA.
  19. """Ref handling.
  20. """
  21. import errno
  22. import os
  23. from dulwich.errors import (
  24. PackedRefsException,
  25. RefFormatError,
  26. )
  27. from dulwich.objects import (
  28. hex_to_sha,
  29. )
  30. from dulwich.file import (
  31. GitFile,
  32. ensure_dir_exists,
  33. )
  34. SYMREF = 'ref: '
  35. LOCAL_BRANCH_PREFIX = 'refs/heads/'
  36. def check_ref_format(refname):
  37. """Check if a refname is correctly formatted.
  38. Implements all the same rules as git-check-ref-format[1].
  39. [1] http://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
  40. :param refname: The refname to check
  41. :return: True if refname is valid, False otherwise
  42. """
  43. # These could be combined into one big expression, but are listed separately
  44. # to parallel [1].
  45. if '/.' in refname or refname.startswith('.'):
  46. return False
  47. if '/' not in refname:
  48. return False
  49. if '..' in refname:
  50. return False
  51. for c in refname:
  52. if ord(c) < 0o40 or c in '\177 ~^:?*[':
  53. return False
  54. if refname[-1] in '/.':
  55. return False
  56. if refname.endswith('.lock'):
  57. return False
  58. if '@{' in refname:
  59. return False
  60. if '\\' in refname:
  61. return False
  62. return True
  63. class RefsContainer(object):
  64. """A container for refs."""
  65. def set_symbolic_ref(self, name, other):
  66. """Make a ref point at another ref.
  67. :param name: Name of the ref to set
  68. :param other: Name of the ref to point at
  69. """
  70. raise NotImplementedError(self.set_symbolic_ref)
  71. def get_packed_refs(self):
  72. """Get contents of the packed-refs file.
  73. :return: Dictionary mapping ref names to SHA1s
  74. :note: Will return an empty dictionary when no packed-refs file is
  75. present.
  76. """
  77. raise NotImplementedError(self.get_packed_refs)
  78. def get_peeled(self, name):
  79. """Return the cached peeled value of a ref, if available.
  80. :param name: Name of the ref to peel
  81. :return: The peeled value of the ref. If the ref is known not point to a
  82. tag, this will be the SHA the ref refers to. If the ref may point to
  83. a tag, but no cached information is available, None is returned.
  84. """
  85. return None
  86. def import_refs(self, base, other):
  87. for name, value in other.iteritems():
  88. self["%s/%s" % (base, name)] = value
  89. def allkeys(self):
  90. """All refs present in this container."""
  91. raise NotImplementedError(self.allkeys)
  92. def keys(self, base=None):
  93. """Refs present in this container.
  94. :param base: An optional base to return refs under.
  95. :return: An unsorted set of valid refs in this container, including
  96. packed refs.
  97. """
  98. if base is not None:
  99. return self.subkeys(base)
  100. else:
  101. return self.allkeys()
  102. def subkeys(self, base):
  103. """Refs present in this container under a base.
  104. :param base: The base to return refs under.
  105. :return: A set of valid refs in this container under the base; the base
  106. prefix is stripped from the ref names returned.
  107. """
  108. keys = set()
  109. base_len = len(base) + 1
  110. for refname in self.allkeys():
  111. if refname.startswith(base):
  112. keys.add(refname[base_len:])
  113. return keys
  114. def as_dict(self, base=None):
  115. """Return the contents of this container as a dictionary.
  116. """
  117. ret = {}
  118. keys = self.keys(base)
  119. if base is None:
  120. base = ""
  121. for key in keys:
  122. try:
  123. ret[key] = self[("%s/%s" % (base, key)).strip("/")]
  124. except KeyError:
  125. continue # Unable to resolve
  126. return ret
  127. def _check_refname(self, name):
  128. """Ensure a refname is valid and lives in refs or is HEAD.
  129. HEAD is not a valid refname according to git-check-ref-format, but this
  130. class needs to be able to touch HEAD. Also, check_ref_format expects
  131. refnames without the leading 'refs/', but this class requires that
  132. so it cannot touch anything outside the refs dir (or HEAD).
  133. :param name: The name of the reference.
  134. :raises KeyError: if a refname is not HEAD or is otherwise not valid.
  135. """
  136. if name in ('HEAD', 'refs/stash'):
  137. return
  138. if not name.startswith('refs/') or not check_ref_format(name[5:]):
  139. raise RefFormatError(name)
  140. def read_ref(self, refname):
  141. """Read a reference without following any references.
  142. :param refname: The name of the reference
  143. :return: The contents of the ref file, or None if it does
  144. not exist.
  145. """
  146. contents = self.read_loose_ref(refname)
  147. if not contents:
  148. contents = self.get_packed_refs().get(refname, None)
  149. return contents
  150. def read_loose_ref(self, name):
  151. """Read a loose reference and return its contents.
  152. :param name: the refname to read
  153. :return: The contents of the ref file, or None if it does
  154. not exist.
  155. """
  156. raise NotImplementedError(self.read_loose_ref)
  157. def _follow(self, name):
  158. """Follow a reference name.
  159. :return: a tuple of (refname, sha), where refname is the name of the
  160. last reference in the symbolic reference chain
  161. """
  162. contents = SYMREF + name
  163. depth = 0
  164. while contents.startswith(SYMREF):
  165. refname = contents[len(SYMREF):]
  166. contents = self.read_ref(refname)
  167. if not contents:
  168. break
  169. depth += 1
  170. if depth > 5:
  171. raise KeyError(name)
  172. return refname, contents
  173. def __contains__(self, refname):
  174. if self.read_ref(refname):
  175. return True
  176. return False
  177. def __getitem__(self, name):
  178. """Get the SHA1 for a reference name.
  179. This method follows all symbolic references.
  180. """
  181. _, sha = self._follow(name)
  182. if sha is None:
  183. raise KeyError(name)
  184. return sha
  185. def set_if_equals(self, name, old_ref, new_ref):
  186. """Set a refname to new_ref only if it currently equals old_ref.
  187. This method follows all symbolic references if applicable for the
  188. subclass, and can be used to perform an atomic compare-and-swap
  189. operation.
  190. :param name: The refname to set.
  191. :param old_ref: The old sha the refname must refer to, or None to set
  192. unconditionally.
  193. :param new_ref: The new sha the refname will refer to.
  194. :return: True if the set was successful, False otherwise.
  195. """
  196. raise NotImplementedError(self.set_if_equals)
  197. def add_if_new(self, name, ref):
  198. """Add a new reference only if it does not already exist."""
  199. raise NotImplementedError(self.add_if_new)
  200. def __setitem__(self, name, ref):
  201. """Set a reference name to point to the given SHA1.
  202. This method follows all symbolic references if applicable for the
  203. subclass.
  204. :note: This method unconditionally overwrites the contents of a
  205. reference. To update atomically only if the reference has not
  206. changed, use set_if_equals().
  207. :param name: The refname to set.
  208. :param ref: The new sha the refname will refer to.
  209. """
  210. self.set_if_equals(name, None, ref)
  211. def remove_if_equals(self, name, old_ref):
  212. """Remove a refname only if it currently equals old_ref.
  213. This method does not follow symbolic references, even if applicable for
  214. the subclass. It can be used to perform an atomic compare-and-delete
  215. operation.
  216. :param name: The refname to delete.
  217. :param old_ref: The old sha the refname must refer to, or None to delete
  218. unconditionally.
  219. :return: True if the delete was successful, False otherwise.
  220. """
  221. raise NotImplementedError(self.remove_if_equals)
  222. def __delitem__(self, name):
  223. """Remove a refname.
  224. This method does not follow symbolic references, even if applicable for
  225. the subclass.
  226. :note: This method unconditionally deletes the contents of a reference.
  227. To delete atomically only if the reference has not changed, use
  228. remove_if_equals().
  229. :param name: The refname to delete.
  230. """
  231. self.remove_if_equals(name, None)
  232. class DictRefsContainer(RefsContainer):
  233. """RefsContainer backed by a simple dict.
  234. This container does not support symbolic or packed references and is not
  235. threadsafe.
  236. """
  237. def __init__(self, refs):
  238. self._refs = refs
  239. self._peeled = {}
  240. def allkeys(self):
  241. return self._refs.keys()
  242. def read_loose_ref(self, name):
  243. return self._refs.get(name, None)
  244. def get_packed_refs(self):
  245. return {}
  246. def set_symbolic_ref(self, name, other):
  247. self._refs[name] = SYMREF + other
  248. def set_if_equals(self, name, old_ref, new_ref):
  249. if old_ref is not None and self._refs.get(name, None) != old_ref:
  250. return False
  251. realname, _ = self._follow(name)
  252. self._check_refname(realname)
  253. self._refs[realname] = new_ref
  254. return True
  255. def add_if_new(self, name, ref):
  256. if name in self._refs:
  257. return False
  258. self._refs[name] = ref
  259. return True
  260. def remove_if_equals(self, name, old_ref):
  261. if old_ref is not None and self._refs.get(name, None) != old_ref:
  262. return False
  263. del self._refs[name]
  264. return True
  265. def get_peeled(self, name):
  266. return self._peeled.get(name)
  267. def _update(self, refs):
  268. """Update multiple refs; intended only for testing."""
  269. # TODO(dborowitz): replace this with a public function that uses
  270. # set_if_equal.
  271. self._refs.update(refs)
  272. def _update_peeled(self, peeled):
  273. """Update cached peeled refs; intended only for testing."""
  274. self._peeled.update(peeled)
  275. class InfoRefsContainer(RefsContainer):
  276. """Refs container that reads refs from a info/refs file."""
  277. def __init__(self, f):
  278. self._refs = {}
  279. self._peeled = {}
  280. for l in f.readlines():
  281. sha, name = l.rstrip("\n").split("\t")
  282. if name.endswith("^{}"):
  283. name = name[:-3]
  284. if not check_ref_format(name):
  285. raise ValueError("invalid ref name '%s'" % name)
  286. self._peeled[name] = sha
  287. else:
  288. if not check_ref_format(name):
  289. raise ValueError("invalid ref name '%s'" % name)
  290. self._refs[name] = sha
  291. def allkeys(self):
  292. return self._refs.keys()
  293. def read_loose_ref(self, name):
  294. return self._refs.get(name, None)
  295. def get_packed_refs(self):
  296. return {}
  297. def get_peeled(self, name):
  298. try:
  299. return self._peeled[name]
  300. except KeyError:
  301. return self._refs[name]
  302. class DiskRefsContainer(RefsContainer):
  303. """Refs container that reads refs from disk."""
  304. def __init__(self, path):
  305. self.path = path
  306. self._packed_refs = None
  307. self._peeled_refs = None
  308. def __repr__(self):
  309. return "%s(%r)" % (self.__class__.__name__, self.path)
  310. def subkeys(self, base):
  311. keys = set()
  312. path = self.refpath(base)
  313. for root, dirs, files in os.walk(path):
  314. dir = root[len(path):].strip(os.path.sep).replace(os.path.sep, "/")
  315. for filename in files:
  316. refname = ("%s/%s" % (dir, filename)).strip("/")
  317. # check_ref_format requires at least one /, so we prepend the
  318. # base before calling it.
  319. if check_ref_format("%s/%s" % (base, refname)):
  320. keys.add(refname)
  321. for key in self.get_packed_refs():
  322. if key.startswith(base):
  323. keys.add(key[len(base):].strip("/"))
  324. return keys
  325. def allkeys(self):
  326. keys = set()
  327. if os.path.exists(self.refpath("HEAD")):
  328. keys.add("HEAD")
  329. path = self.refpath("")
  330. for root, dirs, files in os.walk(self.refpath("refs")):
  331. dir = root[len(path):].strip(os.path.sep).replace(os.path.sep, "/")
  332. for filename in files:
  333. refname = ("%s/%s" % (dir, filename)).strip("/")
  334. if check_ref_format(refname):
  335. keys.add(refname)
  336. keys.update(self.get_packed_refs())
  337. return keys
  338. def refpath(self, name):
  339. """Return the disk path of a ref.
  340. """
  341. if os.path.sep != "/":
  342. name = name.replace("/", os.path.sep)
  343. return os.path.join(self.path, name)
  344. def get_packed_refs(self):
  345. """Get contents of the packed-refs file.
  346. :return: Dictionary mapping ref names to SHA1s
  347. :note: Will return an empty dictionary when no packed-refs file is
  348. present.
  349. """
  350. # TODO: invalidate the cache on repacking
  351. if self._packed_refs is None:
  352. # set both to empty because we want _peeled_refs to be
  353. # None if and only if _packed_refs is also None.
  354. self._packed_refs = {}
  355. self._peeled_refs = {}
  356. path = os.path.join(self.path, 'packed-refs')
  357. try:
  358. f = GitFile(path, 'rb')
  359. except IOError as e:
  360. if e.errno == errno.ENOENT:
  361. return {}
  362. raise
  363. with f:
  364. first_line = next(iter(f)).rstrip()
  365. if (first_line.startswith("# pack-refs") and " peeled" in
  366. first_line):
  367. for sha, name, peeled in read_packed_refs_with_peeled(f):
  368. self._packed_refs[name] = sha
  369. if peeled:
  370. self._peeled_refs[name] = peeled
  371. else:
  372. f.seek(0)
  373. for sha, name in read_packed_refs(f):
  374. self._packed_refs[name] = sha
  375. return self._packed_refs
  376. def get_peeled(self, name):
  377. """Return the cached peeled value of a ref, if available.
  378. :param name: Name of the ref to peel
  379. :return: The peeled value of the ref. If the ref is known not point to a
  380. tag, this will be the SHA the ref refers to. If the ref may point to
  381. a tag, but no cached information is available, None is returned.
  382. """
  383. self.get_packed_refs()
  384. if self._peeled_refs is None or name not in self._packed_refs:
  385. # No cache: no peeled refs were read, or this ref is loose
  386. return None
  387. if name in self._peeled_refs:
  388. return self._peeled_refs[name]
  389. else:
  390. # Known not peelable
  391. return self[name]
  392. def read_loose_ref(self, name):
  393. """Read a reference file and return its contents.
  394. If the reference file a symbolic reference, only read the first line of
  395. the file. Otherwise, only read the first 40 bytes.
  396. :param name: the refname to read, relative to refpath
  397. :return: The contents of the ref file, or None if the file does not
  398. exist.
  399. :raises IOError: if any other error occurs
  400. """
  401. filename = self.refpath(name)
  402. try:
  403. with GitFile(filename, 'rb') as f:
  404. header = f.read(len(SYMREF))
  405. if header == SYMREF:
  406. # Read only the first line
  407. return header + next(iter(f)).rstrip("\r\n")
  408. else:
  409. # Read only the first 40 bytes
  410. return header + f.read(40 - len(SYMREF))
  411. except IOError as e:
  412. if e.errno == errno.ENOENT:
  413. return None
  414. raise
  415. def _remove_packed_ref(self, name):
  416. if self._packed_refs is None:
  417. return
  418. filename = os.path.join(self.path, 'packed-refs')
  419. # reread cached refs from disk, while holding the lock
  420. f = GitFile(filename, 'wb')
  421. try:
  422. self._packed_refs = None
  423. self.get_packed_refs()
  424. if name not in self._packed_refs:
  425. return
  426. del self._packed_refs[name]
  427. if name in self._peeled_refs:
  428. del self._peeled_refs[name]
  429. write_packed_refs(f, self._packed_refs, self._peeled_refs)
  430. f.close()
  431. finally:
  432. f.abort()
  433. def set_symbolic_ref(self, name, other):
  434. """Make a ref point at another ref.
  435. :param name: Name of the ref to set
  436. :param other: Name of the ref to point at
  437. """
  438. self._check_refname(name)
  439. self._check_refname(other)
  440. filename = self.refpath(name)
  441. try:
  442. f = GitFile(filename, 'wb')
  443. try:
  444. f.write(SYMREF + other + '\n')
  445. except (IOError, OSError):
  446. f.abort()
  447. raise
  448. finally:
  449. f.close()
  450. def set_if_equals(self, name, old_ref, new_ref):
  451. """Set a refname to new_ref only if it currently equals old_ref.
  452. This method follows all symbolic references, and can be used to perform
  453. an atomic compare-and-swap operation.
  454. :param name: The refname to set.
  455. :param old_ref: The old sha the refname must refer to, or None to set
  456. unconditionally.
  457. :param new_ref: The new sha the refname will refer to.
  458. :return: True if the set was successful, False otherwise.
  459. """
  460. self._check_refname(name)
  461. try:
  462. realname, _ = self._follow(name)
  463. except KeyError:
  464. realname = name
  465. filename = self.refpath(realname)
  466. ensure_dir_exists(os.path.dirname(filename))
  467. with GitFile(filename, 'wb') as f:
  468. if old_ref is not None:
  469. try:
  470. # read again while holding the lock
  471. orig_ref = self.read_loose_ref(realname)
  472. if orig_ref is None:
  473. orig_ref = self.get_packed_refs().get(realname, None)
  474. if orig_ref != old_ref:
  475. f.abort()
  476. return False
  477. except (OSError, IOError):
  478. f.abort()
  479. raise
  480. try:
  481. f.write(new_ref + "\n")
  482. except (OSError, IOError):
  483. f.abort()
  484. raise
  485. return True
  486. def add_if_new(self, name, ref):
  487. """Add a new reference only if it does not already exist.
  488. This method follows symrefs, and only ensures that the last ref in the
  489. chain does not exist.
  490. :param name: The refname to set.
  491. :param ref: The new sha the refname will refer to.
  492. :return: True if the add was successful, False otherwise.
  493. """
  494. try:
  495. realname, contents = self._follow(name)
  496. if contents is not None:
  497. return False
  498. except KeyError:
  499. realname = name
  500. self._check_refname(realname)
  501. filename = self.refpath(realname)
  502. ensure_dir_exists(os.path.dirname(filename))
  503. with GitFile(filename, 'wb') as f:
  504. if os.path.exists(filename) or name in self.get_packed_refs():
  505. f.abort()
  506. return False
  507. try:
  508. f.write(ref + "\n")
  509. except (OSError, IOError):
  510. f.abort()
  511. raise
  512. return True
  513. def remove_if_equals(self, name, old_ref):
  514. """Remove a refname only if it currently equals old_ref.
  515. This method does not follow symbolic references. It can be used to
  516. perform an atomic compare-and-delete operation.
  517. :param name: The refname to delete.
  518. :param old_ref: The old sha the refname must refer to, or None to delete
  519. unconditionally.
  520. :return: True if the delete was successful, False otherwise.
  521. """
  522. self._check_refname(name)
  523. filename = self.refpath(name)
  524. ensure_dir_exists(os.path.dirname(filename))
  525. f = GitFile(filename, 'wb')
  526. try:
  527. if old_ref is not None:
  528. orig_ref = self.read_loose_ref(name)
  529. if orig_ref is None:
  530. orig_ref = self.get_packed_refs().get(name, None)
  531. if orig_ref != old_ref:
  532. return False
  533. # may only be packed
  534. try:
  535. os.remove(filename)
  536. except OSError as e:
  537. if e.errno != errno.ENOENT:
  538. raise
  539. self._remove_packed_ref(name)
  540. finally:
  541. # never write, we just wanted the lock
  542. f.abort()
  543. return True
  544. def _split_ref_line(line):
  545. """Split a single ref line into a tuple of SHA1 and name."""
  546. fields = line.rstrip("\n").split(" ")
  547. if len(fields) != 2:
  548. raise PackedRefsException("invalid ref line '%s'" % line)
  549. sha, name = fields
  550. try:
  551. hex_to_sha(sha)
  552. except (AssertionError, TypeError) as e:
  553. raise PackedRefsException(e)
  554. if not check_ref_format(name):
  555. raise PackedRefsException("invalid ref name '%s'" % name)
  556. return (sha, name)
  557. def read_packed_refs(f):
  558. """Read a packed refs file.
  559. :param f: file-like object to read from
  560. :return: Iterator over tuples with SHA1s and ref names.
  561. """
  562. for l in f:
  563. if l[0] == "#":
  564. # Comment
  565. continue
  566. if l[0] == "^":
  567. raise PackedRefsException(
  568. "found peeled ref in packed-refs without peeled")
  569. yield _split_ref_line(l)
  570. def read_packed_refs_with_peeled(f):
  571. """Read a packed refs file including peeled refs.
  572. Assumes the "# pack-refs with: peeled" line was already read. Yields tuples
  573. with ref names, SHA1s, and peeled SHA1s (or None).
  574. :param f: file-like object to read from, seek'ed to the second line
  575. """
  576. last = None
  577. for l in f:
  578. if l[0] == "#":
  579. continue
  580. l = l.rstrip("\r\n")
  581. if l[0] == "^":
  582. if not last:
  583. raise PackedRefsException("unexpected peeled ref line")
  584. try:
  585. hex_to_sha(l[1:])
  586. except (AssertionError, TypeError) as e:
  587. raise PackedRefsException(e)
  588. sha, name = _split_ref_line(last)
  589. last = None
  590. yield (sha, name, l[1:])
  591. else:
  592. if last:
  593. sha, name = _split_ref_line(last)
  594. yield (sha, name, None)
  595. last = l
  596. if last:
  597. sha, name = _split_ref_line(last)
  598. yield (sha, name, None)
  599. def write_packed_refs(f, packed_refs, peeled_refs=None):
  600. """Write a packed refs file.
  601. :param f: empty file-like object to write to
  602. :param packed_refs: dict of refname to sha of packed refs to write
  603. :param peeled_refs: dict of refname to peeled value of sha
  604. """
  605. if peeled_refs is None:
  606. peeled_refs = {}
  607. else:
  608. f.write('# pack-refs with: peeled\n')
  609. for refname in sorted(packed_refs.iterkeys()):
  610. f.write('%s %s\n' % (packed_refs[refname], refname))
  611. if refname in peeled_refs:
  612. f.write('^%s\n' % peeled_refs[refname])
  613. def read_info_refs(f):
  614. ret = {}
  615. for l in f.readlines():
  616. (sha, name) = l.rstrip("\r\n").split("\t", 1)
  617. ret[name] = sha
  618. return ret
  619. def write_info_refs(refs, store):
  620. """Generate info refs."""
  621. for name, sha in sorted(refs.items()):
  622. # get_refs() includes HEAD as a special case, but we don't want to
  623. # advertise it
  624. if name == 'HEAD':
  625. continue
  626. try:
  627. o = store[sha]
  628. except KeyError:
  629. continue
  630. peeled = store.peel_sha(sha)
  631. yield '%s\t%s\n' % (o.id, name)
  632. if o.id != peeled.id:
  633. yield '%s\t%s^{}\n' % (peeled.id, name)
  634. is_local_branch = lambda x: x.startswith("refs/heads/")