2
0

refs.py 25 KB

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