1. 16 10月, 2017 5 次提交
  2. 07 10月, 2017 1 次提交
    • J
      refs_resolve_ref_unsafe: handle d/f conflicts for writes · a1c1d817
      Jeff King 提交于
      If our call to refs_read_raw_ref() fails, we check errno to
      see if the ref is simply missing, or if we encountered a
      more serious error. If it's just missing, then in "write"
      mode (i.e., when RESOLVE_REFS_READING is not set), this is
      perfectly fine.
      
      However, checking for ENOENT isn't sufficient to catch all
      missing-ref cases. In the filesystem backend, we may also
      see EISDIR when we try to resolve "a" and "a/b" exists.
      Likewise, we may see ENOTDIR if we try to resolve "a/b" and
      "a" exists. In both of those cases, we know that our
      resolved ref doesn't exist, but we return an error (rather
      than reporting the refname and returning a null sha1).
      
      This has been broken for a long time, but nobody really
      noticed because the next step after resolving without the
      READING flag is usually to lock the ref and write it. But in
      both of those cases, the write will fail with the same
      errno due to the directory/file conflict.
      
      There are two cases where we can notice this, though:
      
        1. If we try to write "a" and there's a leftover directory
           already at "a", even though there is no ref "a/b". The
           actual write is smart enough to move the empty "a" out
           of the way.
      
           This is reasonably rare, if only because the writing
           code has to do an independent resolution before trying
           its write (because the actual update_ref() code handles
           this case fine). The notes-merge code does this, and
           before the fix in the prior commit t3308 erroneously
           expected this case to fail.
      
        2. When resolving symbolic refs, we typically do not use
           the READING flag because we want to resolve even
           symrefs that point to unborn refs. Even if those unborn
           refs could not actually be written because of d/f
           conflicts with existing refs.
      
           You can see this by asking "git symbolic-ref" to report
           the target of a symref pointing past a d/f conflict.
      
      We can fix the problem by recognizing the other "missing"
      errnos and treating them like ENOENT. This should be safe to
      do even for callers who are then going to actually write the
      ref, because the actual writing process will fail if the d/f
      conflict is a real one (and t1404 checks these cases).
      
      Arguably this should be the responsibility of the
      files-backend to normalize all "missing ref" errors into
      ENOENT (since something like EISDIR may not be meaningful at
      all to a database backend). However other callers of
      refs_read_raw_ref() may actually care about the distinction;
      putting this into resolve_ref() is the minimal fix for now.
      
      The new tests in t1401 use git-symbolic-ref, which is the
      most direct way to check the resolution by itself.
      Interestingly we actually had a test that setup this case
      already, but we only used it to verify that the funny state
      could be overwritten, not that it could be resolved.
      
      We also add a new test in t3200, as "branch -m" was the
      original motivation for looking into this. What happens is
      this:
      
        0. HEAD is pointing to branch "a"
      
        1. The user asks to rename "a" to "a/b".
      
        2. We create "a/b" and delete "a".
      
        3. We then try to update any worktree HEADs that point to
           the renamed ref (including the main repo HEAD). To do
           that, we have to resolve each HEAD. But now our HEAD is
           pointing at "a", and we get EISDIR due to the loose
           "a/b". As a result, we think there is no HEAD, and we
           do not update it. It now points to the bogus "a".
      
      Interestingly this case used to work, but only accidentally.
      Before 31824d18 (branch: fix branch renaming not updating
      HEADs correctly, 2017-08-24), we'd update any HEAD which we
      couldn't resolve. That was wrong, but it papered over the
      fact that we were incorrectly failing to resolve HEAD.
      
      So while the bug demonstrated by the git-symbolic-ref is
      quite old, the regression to "branch -m" is recent.
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      a1c1d817
  3. 25 9月, 2017 1 次提交
    • M
      ref_store: implement `refs_peel_ref()` generically · ba1c052f
      Michael Haggerty 提交于
      We're about to stop storing packed refs in a `ref_cache`. That means
      that the only way we have left to optimize `peel_ref()` is by checking
      whether the reference being peeled is the one currently being iterated
      over (in `current_ref_iter`), and if so, using `ref_iterator_peel()`.
      But this can be done generically; it doesn't have to be implemented
      per-backend.
      
      So implement `refs_peel_ref()` in `refs.c` and remove the `peel_ref()`
      method from the refs API.
      
      This removes the last callers of a couple of functions, so delete
      them. More cleanup to come...
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      ba1c052f
  4. 24 9月, 2017 2 次提交
  5. 14 9月, 2017 4 次提交
    • M
      ref_iterator: keep track of whether the iterator output is ordered · 8738a8a4
      Michael Haggerty 提交于
      References are iterated over in order by refname, but reflogs are not.
      Some consumers of reference iteration care about the difference. Teach
      each `ref_iterator` to keep track of whether its output is ordered.
      
      `overlay_ref_iterator` is one of the picky consumers. Add a sanity
      check in `overlay_ref_iterator_begin()` to verify that its inputs are
      ordered.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      8738a8a4
    • J
      avoid "write_in_full(fd, buf, len) != len" pattern · 06f46f23
      Jeff King 提交于
      The return value of write_in_full() is either "-1", or the
      requested number of bytes[1]. If we make a partial write
      before seeing an error, we still return -1, not a partial
      value. This goes back to f6aa66cb (write_in_full: really
      write in full or return error on disk full., 2007-01-11).
      
      So checking anything except "was the return value negative"
      is pointless. And there are a couple of reasons not to do
      so:
      
        1. It can do a funny signed/unsigned comparison. If your
           "len" is signed (e.g., a size_t) then the compiler will
           promote the "-1" to its unsigned variant.
      
           This works out for "!= len" (unless you really were
           trying to write the maximum size_t bytes), but is a
           bug if you check "< len" (an example of which was fixed
           recently in config.c).
      
           We should avoid promoting the mental model that you
           need to check the length at all, so that new sites are
           not tempted to copy us.
      
        2. Checking for a negative value is shorter to type,
           especially when the length is an expression.
      
        3. Linus says so. In d34cf19b (Clean up write_in_full()
           users, 2007-01-11), right after the write_in_full()
           semantics were changed, he wrote:
      
             I really wish every "write_in_full()" user would just
             check against "<0" now, but this fixes the nasty and
             stupid ones.
      
           Appeals to authority aside, this makes it clear that
           writing it this way does not have an intentional
           benefit. It's a historical curiosity that we never
           bothered to clean up (and which was undoubtedly
           cargo-culted into new sites).
      
      So let's convert these obviously-correct cases (this
      includes write_str_in_full(), which is just a wrapper for
      write_in_full()).
      
      [1] A careful reader may notice there is one way that
          write_in_full() can return a different value. If we ask
          write() to write N bytes and get a return value that is
          _larger_ than N, we could return a larger total. But
          besides the fact that this would imply a totally broken
          version of write(), it would already invoke undefined
          behavior. Our internal remaining counter is an unsigned
          size_t, which means that subtracting too many byte will
          wrap it around to a very large number. So we'll instantly
          begin reading off the end of the buffer, trying to write
          gigabytes (or petabytes) of data.
      Signed-off-by: NJeff King <peff@peff.net>
      Reviewed-by: NJonathan Nieder <jrnieder@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      06f46f23
    • S
      replace-objects: evaluate replacement refs without using the object store · 006f3f28
      Stefan Beller 提交于
      Pass DO_FOR_EACH_INCLUDE_BROKEN when iterating over replacement refs
      so that the iteration does not require opening the named objects from
      the object store. This avoids a dependency cycle between object access
      and replace ref iteration.
      
      Moreover the ref subsystem has not been migrated yet to access the
      object store via passed in repository objects.  As a result, without
      this patch, iterating over replace refs in a repository other than
      the_repository it produces errors:
      
         error: refs/replace/3afabef75c627b894cccc3bcae86837abc7c32fe does not point to a valid object!
      
      Noticed while adapting the object store (and in particular its
      evaluation of replace refs) to handle arbitrary repositories.
      Signed-off-by: NStefan Beller <sbeller@google.com>
      Signed-off-by: NJonathan Nieder <jrnieder@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      006f3f28
    • T
      refs: strip out not allowed flags from ref_transaction_update · c788c54c
      Thomas Gummerer 提交于
      Callers are only allowed to pass certain flags into
      ref_transaction_update, other flags are internal to it.  To prevent
      mistakes from the callers, strip the internal only flags out before
      continuing.
      
      This was noticed because of a compiler warning gcc 7.1.1 issued about
      passing a NULL parameter as second parameter to memcpy (through
      hashcpy):
      
      In file included from refs.c:5:0:
      refs.c: In function ‘ref_transaction_verify’:
      cache.h:948:2: error: argument 2 null where non-null expected [-Werror=nonnull]
        memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      In file included from git-compat-util.h:165:0,
                       from cache.h:4,
                       from refs.c:5:
      /usr/include/string.h:43:14: note: in a call to function ‘memcpy’ declared here
       extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
                    ^~~~~~
      
      The call to hascpy in ref_transaction_add_update is protected by the
      passed in flags, but as we only add flags there, gcc notices
      REF_HAVE_NEW or REF_HAVE_OLD flags could be passed in from the outside,
      which would potentially result in passing in NULL as second parameter to
      memcpy.
      
      Fix both the compiler warning, and make the interface safer for its
      users by stripping the internal flags out.
      Suggested-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NThomas Gummerer <t.gummerer@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      c788c54c
  6. 07 9月, 2017 1 次提交
  7. 25 8月, 2017 9 次提交
  8. 24 8月, 2017 1 次提交
    • M
      refs: retry acquiring reference locks for 100ms · 4ff0f01c
      Michael Haggerty 提交于
      The philosophy of reference locking has been, "if another process is
      changing a reference, then whatever I'm trying to do to it will
      probably fail anyway because my old-SHA-1 value is probably no longer
      current". But this argument falls down if the other process has locked
      the reference to do something that doesn't actually change the value
      of the reference, such as `pack-refs` or `reflog expire`. There
      actually *is* a decent chance that a planned reference update will
      still be able to go through after the other process has released the
      lock.
      
      So when trying to lock an individual reference (e.g., when creating
      "refs/heads/master.lock"), if it is already locked, then retry the
      lock acquisition for approximately 100 ms before giving up. This
      should eliminate some unnecessary lock conflicts without wasting a lot
      of time.
      
      Add a configuration setting, `core.filesRefLockTimeout`, to allow this
      setting to be tweaked.
      
      Note: the function `get_files_ref_lock_timeout_ms()` cannot be private
      to the files backend because it is also used by `write_pseudoref()`
      and `delete_pseudoref()`, which are defined in `refs.c` so that they
      can be used by other reference backends.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      4ff0f01c
  9. 25 7月, 2017 1 次提交
  10. 18 7月, 2017 1 次提交
  11. 01 7月, 2017 1 次提交
    • S
      hashmap.h: compare function has access to a data field · 7663cdc8
      Stefan Beller 提交于
      When using the hashmap a common need is to have access to caller provided
      data in the compare function. A couple of times we abuse the keydata field
      to pass in the data needed. This happens for example in patch-ids.c.
      
      This patch changes the function signature of the compare function
      to have one more void pointer available. The pointer given for each
      invocation of the compare function must be defined in the init function
      of the hashmap and is just passed through.
      
      Documentation of this new feature is deferred to a later patch.
      This is a rather mechanical conversion, just adding the new pass-through
      parameter.  However while at it improve the naming of the fields of all
      compare functions used by hashmaps by ensuring unused parameters are
      prefixed with 'unused_' and naming the parameters what they are (instead
      of 'unused' make it 'unused_keydata').
      Signed-off-by: NStefan Beller <sbeller@google.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      7663cdc8
  12. 24 6月, 2017 2 次提交
  13. 19 6月, 2017 2 次提交
    • M
      for_each_bisect_ref(): don't trim refnames · 03df567f
      Michael Haggerty 提交于
      `for_each_bisect_ref()` is called by `for_each_bad_bisect_ref()` with
      a term "bad". This used to make it call `for_each_ref_in_submodule()`
      with a prefix "refs/bisect/bad". But the latter is the name of the
      reference that is being sought, so the empty string was being passed
      to the callback as the trimmed refname. Moreover, this questionable
      practice was turned into an error by
      
          b9c8e7f2 prefix_ref_iterator: don't trim too much, 2017-05-22
      
      It makes more sense (and agrees better with the documentation of
      `--bisect`) for the callers to receive the full reference names. So
      
      * Add a new function, `for_each_fullref_in_submodule()`, to the refs
        API. This plugs a gap in the existing functionality, analogous to
        `for_each_fullref_in()` but accepting a `submodule` argument.
      
      * Change `for_each_bad_bisect_ref()` to call the new function rather
        than `for_each_ref_in_submodule()`.
      
      * Add a test.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      03df567f
    • S
      branch: add a --copy (-c) option to go with --move (-m) · 52d59cc6
      Sahil Dua 提交于
      Add the ability to --copy a branch and its reflog and configuration,
      this uses the same underlying machinery as the --move (-m) option
      except the reflog and configuration is copied instead of being moved.
      
      This is useful for e.g. copying a topic branch to a new version,
      e.g. work to work-2 after submitting the work topic to the list, while
      preserving all the tracking info and other configuration that goes
      with the branch, and unlike --move keeping the other already-submitted
      branch around for reference.
      
      Like --move, when the source branch is the currently checked out
      branch the HEAD is moved to the destination branch. In the case of
      --move we don't really have a choice (other than remaining on a
      detached HEAD) and in order to keep the functionality consistent, we
      are doing it in similar way for --copy too.
      
      The most common usage of this feature is expected to be moving to a
      new topic branch which is a copy of the current one, in that case
      moving to the target branch is what the user wants, and doesn't
      unexpectedly behave differently than --move would.
      
      One outstanding caveat of this implementation is that:
      
          git checkout maint &&
          git checkout master &&
          git branch -c topic &&
          git checkout -
      
      Will check out 'maint' instead of 'master'. This is because the @{-N}
      feature (or its -1 shorthand "-") relies on HEAD reflogs created by
      the checkout command, so in this case we'll checkout maint instead of
      master, as the user might expect. What to do about that is left to a
      future change.
      Helped-by: NÆvar Arnfjörð Bjarmason <avarab@gmail.com>
      Signed-off-by: NÆvar Arnfjörð Bjarmason <avarab@gmail.com>
      Signed-off-by: NSahil Dua <sahildua2305@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      52d59cc6
  14. 16 6月, 2017 1 次提交
  15. 23 5月, 2017 8 次提交