1. 10 9月, 2016 31 次提交
  2. 21 6月, 2016 9 次提交
    • M
      for_each_reflog(): reimplement using iterators · 2880d16f
      Michael Haggerty 提交于
      Allow references with reflogs to be iterated over using a ref_iterator.
      The latter is implemented as a files_reflog_iterator, which in turn uses
      dir_iterator to read the "logs" directory.
      
      Note that reflog iteration doesn't correctly handle per-worktree
      reflogs (either before or after this patch).
      Signed-off-by: NRamsay Jones <ramsay@ramsayjones.plus.com>
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      2880d16f
    • M
      dir_iterator: new API for iterating over a directory tree · 0fe5043d
      Michael Haggerty 提交于
      The iterator interface is modeled on that for references, though no
      vtable is necessary because there is (so far?) only one type of
      dir_iterator.
      
      There are obviously a lot of features that could easily be added to this
      class:
      
      * Skip/include directory paths in the iteration
      * Shallow/deep iteration
      * Letting the caller decide which subdirectories to recurse into (e.g.,
        via a dir_iterator_advance_into() function)
      * Option to iterate in sorted order
      * Option to iterate over directory paths before vs. after their contents
      
      But these are not needed for the current patch series, so I refrain.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      0fe5043d
    • M
      for_each_reflog(): don't abort for bad references · d24b21e9
      Michael Haggerty 提交于
      If there is a file under "$GIT_DIR/logs" with no corresponding
      reference, the old code was emitting an error message, aborting the
      reflog iteration, and returning -1. But
      
      * None of the callers was checking the exit value
      
      * The callers all want to find all legitimate reflogs (sometimes for the
        purpose of determining object reachability!) and wouldn't benefit from
        a truncated iteration anyway.
      
      So instead, emit an error message and skip the "broken" reflog, but
      continue with the iteration.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      d24b21e9
    • M
      do_for_each_ref(): reimplement using reference iteration · 4c4de895
      Michael Haggerty 提交于
      Use the reference iterator interface to implement do_for_each_ref().
      Delete a bunch of code supporting the old for_each_ref() implementation.
      And now that do_for_each_ref() is generic code (it is no longer tied to
      the files backend), move it to refs.c.
      
      The implementation is via a new function, do_for_each_ref_iterator(),
      which takes a reference iterator as argument and calls a callback
      function for each of the references in the iterator.
      
      This change requires the current_ref performance hack for peel_ref() to
      be implemented via ref_iterator_peel() rather than peel_entry() because
      we don't have a ref_entry handy (it is hidden under three layers:
      file_ref_iterator, merge_ref_iterator, and cache_ref_iterator). So:
      
      * do_for_each_ref_iterator() records the active iterator in
        current_ref_iter while it is running.
      
      * peel_ref() checks whether current_ref_iter is pointing at the
        requested reference. If so, it asks the iterator to peel the
        reference (which it can do efficiently via its "peel" virtual
        function). For extra safety, we do the optimization only if the
        refname *addresses* are the same, not only if the refname *strings*
        are the same, to forestall possible mixups between refnames that come
        from different ref_iterators.
      
      Please note that this optimization of peel_ref() is only available when
      iterating via do_for_each_ref_iterator() (including all of the
      for_each_ref() functions, which call it indirectly). It would be
      complicated to implement a similar optimization when iterating directly
      using a reference iterator, because multiple reference iterators can be
      in use at the same time, with interleaved calls to
      ref_iterator_advance(). (In fact we do exactly that in
      merge_ref_iterator.)
      
      But that is not necessary. peel_ref() is only called while iterating
      over references. Callers who iterate using the for_each_ref() functions
      benefit from the optimization described above. Callers who iterate using
      reference iterators directly have access to the ref_iterator, so they
      can call ref_iterator_peel() themselves to get an analogous optimization
      in a more straightforward manner.
      
      If we rewrite all callers to use the reference iteration API, then we
      can remove the current_ref_iter hack permanently.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      4c4de895
    • M
      refs: introduce an iterator interface · 3bc581b9
      Michael Haggerty 提交于
      Currently, the API for iterating over references is via a family of
      for_each_ref()-type functions that invoke a callback function for each
      selected reference. All of these eventually call do_for_each_ref(),
      which knows how to do one thing: iterate in parallel through two
      ref_caches, one for loose and one for packed refs, giving loose
      references precedence over packed refs. This is rather complicated code,
      and is quite specialized to the files backend. It also requires callers
      to encapsulate their work into a callback function, which often means
      that they have to define and use a "cb_data" struct to manage their
      context.
      
      The current design is already bursting at the seams, and will become
      even more awkward in the upcoming world of multiple reference storage
      backends:
      
      * Per-worktree vs. shared references are currently handled via a kludge
        in git_path() rather than iterating over each part of the reference
        namespace separately and merging the results. This kludge will cease
        to work when we have multiple reference storage backends.
      
      * The current scheme is inflexible. What if we sometimes want to bypass
        the ref_cache, or use it only for packed or only for loose refs? What
        if we want to store symbolic refs in one type of storage backend and
        non-symbolic ones in another?
      
      In the future, each reference backend will need to define its own way of
      iterating over references. The crux of the problem with the current
      design is that it is impossible to compose for_each_ref()-style
      iterations, because the flow of control is owned by the for_each_ref()
      function. There is nothing that a caller can do but iterate through all
      references in a single burst, so there is no way for it to interleave
      references from multiple backends and present the result to the rest of
      the world as a single compound backend.
      
      This commit introduces a new iteration primitive for references: a
      ref_iterator. A ref_iterator is a polymorphic object that a reference
      storage backend can be asked to instantiate. There are three functions
      that can be applied to a ref_iterator:
      
      * ref_iterator_advance(): move to the next reference in the iteration
      * ref_iterator_abort(): end the iteration before it is exhausted
      * ref_iterator_peel(): peel the reference currently being looked at
      
      Iterating using a ref_iterator leaves the flow of control in the hands
      of the caller, which means that ref_iterators from multiple
      sources (e.g., loose and packed refs) can be composed and presented to
      the world as a single compound ref_iterator.
      
      It also means that the backend code for implementing reference iteration
      will sometimes be more complicated. For example, the
      cache_ref_iterator (which iterates over a ref_cache) can't use the C
      stack to recurse; instead, it must manage its own stack internally as
      explicit data structures. There is also a lot of boilerplate connected
      with object-oriented programming in C.
      
      Eventually, end-user callers will be able to be written in a more
      natural way—managing their own flow of control rather than having to
      work via callbacks. Since there will only be a few reference backends
      but there are many consumers of this API, this is a good tradeoff.
      
      More importantly, we gain composability, and especially the possibility
      of writing interchangeable parts that can work with any ref_iterator.
      
      For example, merge_ref_iterator implements a generic way of merging the
      contents of any two ref_iterators. It is used to merge loose + packed
      refs as part of the implementation of the files_ref_iterator. But it
      will also be possible to use it to merge other pairs of reference
      sources (e.g., per-worktree vs. shared refs).
      
      Another example is prefix_ref_iterator, which can be used to trim a
      prefix off the front of reference names before presenting them to the
      caller (e.g., "refs/heads/master" -> "master").
      
      In this patch, we introduce the iterator abstraction and many utilities,
      and implement a reference iterator for the files ref storage backend.
      (I've written several other obvious utilities, for example a generic way
      to filter references being iterated over. These will probably be useful
      in the future. But they are not needed for this patch series, so I am
      not including them at this time.)
      
      In a moment we will rewrite do_for_each_ref() to work via reference
      iterators (allowing some special-purpose code to be discarded), and do
      something similar for reflogs. In future patch series, we will expose
      the ref_iterator abstraction in the public refs API so that callers can
      use it directly.
      
      Implementation note: I tried abstracting this a layer further to allow
      generic iterators (over arbitrary types of objects) and generic
      utilities like a generic merge_iterator. But the implementation in C was
      very cumbersome, involving (in my opinion) too much boilerplate and too
      much unsafe casting, some of which would have had to be done on the
      caller side. However, I did put a few iterator-related constants in a
      top-level header file, iterator.h, as they will be useful in a moment to
      implement iteration over directory trees and possibly other types of
      iterators in the future.
      Signed-off-by: NRamsay Jones <ramsay@ramsayjones.plus.com>
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      3bc581b9
    • M
      ref_resolves_to_object(): new function · a8739244
      Michael Haggerty 提交于
      Extract new function ref_resolves_to_object() from
      entry_resolves_to_object(). It can be used even if there is no ref_entry
      at hand.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      a8739244
    • M
      entry_resolves_to_object(): rename function from ref_resolves_to_object() · ffeef642
      Michael Haggerty 提交于
      Free up the old name for a more general purpose.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      ffeef642
    • M
      get_ref_cache(): only create an instance if there is a submodule · 2eed2780
      Michael Haggerty 提交于
      If there is not a nonbare repository where a submodule is supposedly
      located, then don't instantiate a ref_cache for it.
      
      The analogous check can be removed from resolve_gitlink_ref().
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      2eed2780
    • M
      remote rm: handle symbolic refs correctly · 29a7cf96
      Michael Haggerty 提交于
      In the modern world of reference backends, it is not OK to delete a
      symref by unlink()ing the file directly. This must be done via the refs
      API.
      
      We do so by adding the symref to the list of references to delete along
      with the non-symbolic references, then calling delete_refs() with the
      new flags option set to REF_NODEREF.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      29a7cf96