1. 23 5月, 2018 1 次提交
  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. 03 9月, 2016 1 次提交
    • J
      symbolic-ref -d: do not allow removal of HEAD · 12cfa792
      Junio C Hamano 提交于
      If you delete the symbolic-ref HEAD from a repository, Git no longer
      considers the repository valid, and even "git symbolic-ref HEAD
      refs/heads/master" would not be able to recover from that state
      (although "git init" can, but that is a sure sign that you are
      talking about a "broken" repository).
      
      In the spirit similar to afe5d3d5 ("symbolic ref: refuse non-ref
      targets in HEAD", 2009-01-29), forbid removal of HEAD to avoid
      corrupting a repository.
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      12cfa792
  4. 07 6月, 2016 1 次提交
    • S
      reflog: continue walking the reflog past root commits · 71abeb75
      SZEDER Gábor 提交于
      If a repository contains more than one root commit, then its HEAD
      reflog may contain multiple "creation events", i.e. entries whose
      "from" value is the null sha1.  Listing such a reflog currently stops
      prematurely at the first such entry, even when the reflog still
      contains older entries.  This can scare users into thinking that their
      reflog got truncated after 'git checkout --orphan'.
      
      Continue walking the reflog past such creation events based on the
      preceeding reflog entry's "new" value.
      
      The test 'symbolic-ref writes reflog entry' in t1401-symbolic-ref
      implicitly relies on the current behavior of the reflog walker to stop
      at a root commit and thus to list only the reflog entries that are
      relevant for that test.  Adjust the test to explicitly specify the
      number of relevant reflog entries to be listed.
      Reported-by: NPatrik Gustafsson <pvn@textalk.se>
      Signed-off-by: NSZEDER Gábor <szeder@ira.uka.de>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      71abeb75
  5. 14 1月, 2016 1 次提交
    • J
      lock_ref_sha1_basic: handle REF_NODEREF with invalid refs · 2859dcd4
      Jeff King 提交于
      We sometimes call lock_ref_sha1_basic with REF_NODEREF
      to operate directly on a symbolic ref. This is used, for
      example, to move to a detached HEAD, or when updating
      the contents of HEAD via checkout or symbolic-ref.
      
      However, the first step of the function is to resolve the
      refname to get the "old" sha1, and we do so without telling
      resolve_ref_unsafe() that we are only interested in the
      symref. As a result, we may detect a problem there not with
      the symref itself, but with something it points to.
      
      The real-world example I found (and what is used in the test
      suite) is a HEAD pointing to a ref that cannot exist,
      because it would cause a directory/file conflict with other
      existing refs.  This situation is somewhat broken, of
      course, as trying to _commit_ on that HEAD would fail. But
      it's not explicitly forbidden, and we should be able to move
      away from it. However, neither "git checkout" nor "git
      symbolic-ref" can do so. We try to take the lock on HEAD,
      which is pointing to a non-existent ref. We bail from
      resolve_ref_unsafe() with errno set to EISDIR, and the lock
      code thinks we are attempting to create a d/f conflict.
      
      Of course we're not. The problem is that the lock code has
      no idea what level we were at when we got EISDIR, so trying
      to diagnose or remove empty directories for HEAD is not
      useful.
      
      To make things even more complicated, we only get EISDIR in
      the loose-ref case. If the refs are packed, the resolution
      may "succeed", giving us the pointed-to ref in "refname",
      but a null oid. Later, we say "ah, the null oid means we are
      creating; let's make sure there is room for it", but
      mistakenly check against the _resolved_ refname, not the
      original.
      
      We can fix this by making two tweaks:
      
        1. Call resolve_ref_unsafe() with RESOLVE_REF_NO_RECURSE
           when REF_NODEREF is set. This means any errors
           we get will be from the orig_refname, and we can act
           accordingly.
      
           We already do this in the REF_DELETING case, but we
           should do it for update, too.
      
        2. If we do get a "refname" return from
           resolve_ref_unsafe(), even with RESOLVE_REF_NO_RECURSE
           it may be the name of the ref pointed-to by a symref.
           We already normalize this back to orig_refname before
           taking the lockfile, but we need to do so before the
           null_oid check.
      
      While we're rearranging the REF_NODEREF handling, we can
      also bump the initialization of lflags to the top of the
      function, where we are setting up other flags. This saves us
      from having yet another conditional block on REF_NODEREF
      just to set it later.
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      2859dcd4
  6. 30 12月, 2015 1 次提交
    • J
      create_symref: use existing ref-lock code · 370e5ad6
      Jeff King 提交于
      The create_symref() function predates the existence of
      "struct lock_file", let alone the more recent "struct
      ref_lock". Instead, it just does its own manual dot-locking.
      Besides being more code, this has a few downsides:
      
       - if git is interrupted while holding the lock, we don't
         clean up the lockfile
      
       - we don't do the usual directory/filename conflict check.
         So you can sometimes create a symref "refs/heads/foo/bar",
         even if "refs/heads/foo" exists (namely, if the refs are
         packed and we do not hit the d/f conflict in the
         filesystem).
      
      This patch refactors create_symref() to use the "struct
      ref_lock" interface, which handles both of these things.
      There are a few bonus cleanups that come along with it:
      
       - we leaked ref_path in some error cases
      
       - the symref contents were stored in a fixed-size buffer,
         putting an artificial (albeit large) limitation on the
         length of the refname. We now write through fprintf, and
         handle refnames of any size.
      
       - we called adjust_shared_perm only after the file was
         renamed into place, creating a potential race with
         readers in a shared repository. The lockfile code now
         handles this when creating the lockfile, making it
         atomic.
      
       - the legacy prefer_symlink_refs path did not do any
         locking at all. Admittedly, it is not atomic from a
         reader's perspective (as it unlinks and re-creates the
         symlink to overwrite), but at least it cannot conflict
         with other writers now.
      
       - the result of this patch is hopefully more readable. It
         eliminates three goto labels. Two were for error checking
         that is now simplified, and the third was to reach shared
         code that has been pulled into its own function.
      Signed-off-by: NJeff King <peff@peff.net>
      Reviewed-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      370e5ad6
  7. 28 12月, 2015 1 次提交
  8. 22 12月, 2015 2 次提交
  9. 26 9月, 2015 1 次提交
    • J
      resolve_ref: use strbufs for internal buffers · 495127db
      Jeff King 提交于
      resolve_ref already uses a strbuf internally when generating
      pathnames, but it uses fixed-size buffers for storing the
      refname and symbolic refs. This means that you cannot
      actually point HEAD to a ref that is larger than 256 bytes.
      
      We can lift this limit by using strbufs here, too. Like
      sb_path, we pass the the buffers into our helper function,
      so that we can easily clean up all output paths. We can also
      drop the "unsafe" name from our helper function, as it no
      longer uses a single static buffer (but of course
      resolve_ref_unsafe is still unsafe, because the static
      buffers moved there).
      
      As a bonus, we also get to drop some strcpy calls between
      the two fixed buffers (that cannot currently overflow
      because the two buffers are sized identically).
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      495127db
  10. 22 10月, 2012 1 次提交
    • J
      git symbolic-ref --delete $symref · 9ab55daa
      Johan Herland 提交于
      Teach symbolic-ref to delete symrefs by adding the -d/--delete option to
      git-symbolic-ref. Both proper and dangling symrefs are deleted by this
      option, but other refs - or anything else that is not a symref - is not.
      
      The symref deletion is performed by first verifying that we are given a
      proper symref, and then invoking delete_ref() on it with the REF_NODEREF
      flag.
      Signed-off-by: NJohan Herland <johan@herland.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      9ab55daa
  11. 10 11月, 2010 1 次提交
  12. 14 2月, 2009 1 次提交
    • J
      symbolic-ref: allow refs/<whatever> in HEAD · e9cc02f0
      Jeff King 提交于
      Commit afe5d3d5 introduced a safety valve to symbolic-ref to
      disallow installing an invalid HEAD. It was accompanied by
      b229d18a, which changed validate_headref to require that
      HEAD contain a pointer to refs/heads/ instead of just refs/.
      Therefore, the safety valve also checked for refs/heads/.
      
      As it turns out, topgit is using refs/top-bases/ in HEAD,
      leading us to re-loosen (at least temporarily) the
      validate_headref check made in b229d18a. This patch does the
      corresponding loosening for the symbolic-ref safety valve,
      so that the two are in agreement once more.
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      e9cc02f0
  13. 29 1月, 2009 1 次提交
    • J
      symbolic ref: refuse non-ref targets in HEAD · afe5d3d5
      Jeff King 提交于
      When calling "git symbolic-ref" it is easy to forget that
      the target must be a fully qualified ref. E.g., you might
      accidentally do:
      
        $ git symbolic-ref HEAD master
      
      Unfortunately, this is very difficult to recover from,
      because the bogus contents of HEAD make git believe we are
      no longer in a git repository (as is_git_dir explicitly
      checks for "^refs/heads/" in the HEAD target). So
      immediately trying to fix the situation doesn't work:
      
        $ git symbolic-ref HEAD refs/heads/master
        fatal: Not a git repository
      
      and one is left editing the .git/HEAD file manually.
      
      Furthermore, one might be tempted to use symbolic-ref to set
      up a detached HEAD:
      
        $ git symbolic-ref HEAD `git rev-parse HEAD`
      
      which sets up an even more bogus HEAD:
      
        $ cat .git/HEAD
        ref: 1a9ace4f2ad4176148e61b5a85cd63d5604aac6d
      
      This patch introduces a small safety valve to prevent the
      specific case of anything not starting with refs/heads/ to
      go into HEAD. The scope of the safety valve is intentionally
      very limited, to make sure that we are not preventing any
      behavior that would otherwise be valid (like pointing a
      different symref than HEAD outside of refs/heads/).
      Signed-off-by: NJeff King <peff@peff.net>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      afe5d3d5