1. 09 5月, 2013 1 次提交
    • F
      Add new @ shortcut for HEAD · cdfd9483
      Felipe Contreras 提交于
      Typing 'HEAD' is tedious, especially when we can use '@' instead.
      
      The reason for choosing '@' is that it follows naturally from the
      ref@op syntax (e.g. HEAD@{u}), except we have no ref, and no
      operation, and when we don't have those, it makes sens to assume
      'HEAD'.
      
      So now we can use 'git show @~1', and all that goody goodness.
      
      Until now '@' was a valid name, but it conflicts with this idea, so
      let's make it invalid. Probably very few people, if any, used this name.
      Signed-off-by: NFelipe Contreras <felipe.contreras@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      cdfd9483
  2. 02 5月, 2013 30 次提交
  3. 24 3月, 2013 1 次提交
  4. 18 3月, 2013 1 次提交
    • M
      pack-refs: add fully-peeled trait · c29c46fa
      Michael Haggerty 提交于
      Older versions of pack-refs did not write peel lines for
      refs outside of refs/tags. This meant that on reading the
      pack-refs file, we might set the REF_KNOWS_PEELED flag for
      such a ref, even though we do not know anything about its
      peeled value.
      
      The previous commit updated the writer to always peel, no
      matter what the ref is. That means that packed-refs files
      written by newer versions of git are fine to be read by both
      old and new versions of git. However, we still have the
      problem of reading packed-refs files written by older
      versions of git, or by other implementations which have not
      yet learned the same trick.
      
      The simplest fix would be to always unset the
      REF_KNOWS_PEELED flag for refs outside of refs/tags that do
      not have a peel line (if it has a peel line, we know it is
      valid, but we cannot assume a missing peel line means
      anything). But that loses an important optimization, as
      upload-pack should not need to load the object pointed to by
      refs/heads/foo to determine that it is not a tag.
      
      Instead, we add a "fully-peeled" trait to the packed-refs
      file. If it is set, we know that we can trust a missing peel
      line to mean that a ref cannot be peeled. Otherwise, we fall
      back to assuming nothing.
      
      [commit message and tests by Jeff King <peff@peff.net>]
      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>
      c29c46fa
  5. 09 3月, 2013 3 次提交
    • J
      reflog: add for_each_reflog_ent_reverse() API · 98f85ff4
      Junio C Hamano 提交于
      "git checkout -" is a short-hand for "git checkout @{-1}" and the
      "@{nth}" notation for a negative number is to find nth previous
      checkout in the reflog of the HEAD to determine the name of the
      branch the user was on.  We would want to find the nth most recent
      reflog entry that matches "checkout: moving from X to Y" for this.
      
      Unfortunately, reflog is implemented as an append-only file, and the
      API to iterate over its entries, for_each_reflog_ent(), reads the
      file in order, giving the entries from the oldest to newer.  For the
      purpose of finding nth most recent one, this API forces us to record
      the last n entries in a rotating buffer and give the result out only
      after we read everything.  To optimize for a common case of finding
      the nth most recent one for a small value of n, we also have a side
      API for_each_recent_reflog_ent() that starts reading near the end of
      the file, but it still has to read the entries in the "wrong" order.
      The implementation of understanding @{-1} uses this interface.
      
      This all becomes unnecessary if we add an API to let us iterate over
      reflog entries in the reverse order, from the newest to older.
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      98f85ff4
    • J
      for_each_recent_reflog_ent(): simplify opening of a reflog file · 7ae07c1b
      Junio C Hamano 提交于
      There is no reason to use a temporary variable logfile.
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      7ae07c1b
    • J
      for_each_reflog_ent(): extract a helper to process a single entry · 9a7a183b
      Junio C Hamano 提交于
      Split the logic that takes a single line of reflog entry in a
      strbuf, parses the message, and calls the callback function out of
      the loop into a separate helper function.
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      9a7a183b
  6. 08 2月, 2013 1 次提交
    • J
      upload/receive-pack: allow hiding ref hierarchies · daebaa78
      Junio C Hamano 提交于
      A repository may have refs that are only used for its internal
      bookkeeping purposes that should not be exposed to the others that
      come over the network.
      
      Teach upload-pack to omit some refs from its initial advertisement
      by paying attention to the uploadpack.hiderefs multi-valued
      configuration variable.  Do the same to receive-pack via the
      receive.hiderefs variable.  As a convenient short-hand, allow using
      transfer.hiderefs to set the value to both of these variables.
      
      Any ref that is under the hierarchies listed on the value of these
      variable is excluded from responses to requests made by "ls-remote",
      "fetch", etc. (for upload-pack) and "push" (for receive-pack).
      
      Because these hidden refs do not count as OUR_REF, an attempt to
      fetch objects at the tip of them will be rejected, and because these
      refs do not get advertised, "git push :" will not see local branches
      that have the same name as them as "matching" ones to be sent.
      
      An attempt to update/delete these hidden refs with an explicit
      refspec, e.g. "git push origin :refs/hidden/22", is rejected.  This
      is not a new restriction.  To the pusher, it would appear that there
      is no such ref, so its push request will conclude with "Now that I
      sent you all the data, it is time for you to update the refs.  I saw
      that the ref did not exist when I started pushing, and I want the
      result to point at this commit".  The receiving end will apply the
      compare-and-swap rule to this request and rejects the push with
      "Well, your update request conflicts with somebody else; I see there
      is such a ref.", which is the right thing to do. Otherwise a push to
      a hidden ref will always be "the last one wins", which is not a good
      default.
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      daebaa78
  7. 17 1月, 2013 1 次提交
  8. 22 12月, 2012 1 次提交
    • J
      refs: do not use cached refs in repack_without_ref · b3f1280e
      Jeff King 提交于
      When we delete a ref that is packed, we rewrite the whole
      packed-refs file and simply omit the ref that no longer
      exists. However, we base the rewrite on whatever happens to
      be in our refs cache, not what is necessarily on disk. That
      opens us up to a race condition if another process is
      simultaneously packing the refs, as we will overwrite their
      newly-made pack-refs file with our potentially stale data,
      losing commits.
      
      You can demonstrate the race like this:
      
        # setup some repositories
        git init --bare parent &&
        (cd parent && git config core.logallrefupdates true) &&
        git clone parent child &&
        (cd child && git commit --allow-empty -m base)
      
        # in one terminal, repack the refs repeatedly
        cd parent &&
        while true; do
      	git pack-refs --all
        done
      
        # in another terminal, simultaneously push updates to
        # master, and create and delete an unrelated ref
        cd child &&
        while true; do
      	git push origin HEAD:newbranch &&
      	git commit --allow-empty -m foo
      	us=`git rev-parse master` &&
      	git push origin master &&
      	git push origin :newbranch &&
      	them=`git --git-dir=../parent rev-parse master` &&
      	if test "$them" != "$us"; then
      		echo >&2 "$them" != "$us"
      		exit 1
      	fi
        done
      
      In many cases the two processes will conflict over locking
      the packed-refs file, and the deletion of newbranch will
      simply fail.  But eventually you will hit the race, which
      happens like this:
      
        1. We push a new commit to master. It is already packed
           (from the looping pack-refs call). We write the new
           value (let us call it B) to $GIT_DIR/refs/heads/master,
           but the old value (call it A) remains in the
           packed-refs file.
      
        2. We push the deletion of newbranch, spawning a
           receive-pack process. Receive-pack advertises all refs
           to the client, causing it to iterate over each ref; it
           caches the packed refs in memory, which points at the
           stale value A.
      
        3. Meanwhile, a separate pack-refs process is running. It
           runs to completion, updating the packed-refs file to
           point master at B, and deleting $GIT_DIR/refs/heads/master
           which also pointed at B.
      
        4. Back in the receive-pack process, we get the
           instruction to delete :newbranch. We take a lock on
           packed-refs (which works, as the other pack-refs
           process has already finished). We then rewrite the
           contents using the cached refs, which contain the stale
           value A.
      
      The resulting packed-refs file points master once again at
      A. The loose ref which would override it to point at B was
      deleted (rightfully) in step 3. As a result, master now
      points at A. The only trace that B ever existed in the
      parent is in the reflog: the final entry will show master
      moving from A to B, even though the ref still points at A
      (so you can detect this race after the fact, because the
      next reflog entry will move from A to C).
      
      We can fix this by invalidating the packed-refs cache after
      we have taken the lock. This means that we will re-read the
      packed-refs file, and since we have the lock, we will be
      sure that what we read will be atomically up-to-date when we
      write (it may be out of date with respect to loose refs, but
      that is OK, as loose refs take precedence).
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      b3f1280e
  9. 22 10月, 2012 1 次提交
    • J
      Fix failure to delete a packed ref through a symref · b274a714
      Johan Herland 提交于
      When deleting a ref through a symref (e.g. using 'git update-ref -d HEAD'
      to delete refs/heads/master), we would remove the loose ref, but a packed
      version of the same ref would remain, the end result being that instead of
      deleting refs/heads/master we would appear to reset it to its state as of
      the last repack.
      
      This patch fixes the issue, by making sure we pass the correct ref name
      when invoking repack_without_ref() from within delete_ref().
      Signed-off-by: NJohan Herland <johan@herland.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      b274a714