summaryrefslogtreecommitdiff
path: root/refs.c
Commit message (Collapse)AuthorAgeFilesLines
* Merge branch 'mh/lockfile-retry'Junio C Hamano2015-05-221-1/+11
|\ | | | | | | | | | | | | | | | | Instead of dying immediately upon failing to obtain a lock, retry after a short while with backoff. * mh/lockfile-retry: lock_packed_refs(): allow retries when acquiring the packed-refs lock lockfile: allow file locking to be retried with a timeout
| * lock_packed_refs(): allow retries when acquiring the packed-refs lockmh/lockfile-retryMichael Haggerty2015-05-141-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, there is only one attempt to acquire any lockfile, and if the lock is held by another process, the locking attempt fails immediately. This is not such a limitation for loose reference files. First, they don't take long to rewrite. Second, most reference updates have a known "old" value, so if another process is updating a reference at the same moment that we are trying to lock it, then probably the expected "old" value will not longer be valid, and the update will fail anyway. But these arguments do not hold for packed-refs: * The packed-refs file can be large and take significant time to rewrite. * Many references are stored in a single packed-refs file, so it could be that the other process was changing a different reference than the one that we are interested in. Therefore, it is much more likely for there to be spurious lock conflicts in connection to the packed-refs file, resulting in unnecessary command failures. So, if the first attempt to lock the packed-refs file fails, continue retrying for a configurable length of time before giving up. The default timeout is 1 second. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | Merge branch 'mh/ref-directory-file'Junio C Hamano2015-05-221-111/+198
|\ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The ref API did not handle cases where 'refs/heads/xyzzy/frotz' is removed at the same time as 'refs/heads/xyzzy' is added (or vice versa) very well. * mh/ref-directory-file: reflog_expire(): integrate lock_ref_sha1_basic() errors into ours ref_transaction_commit(): delete extra "the" from error message ref_transaction_commit(): provide better error messages rename_ref(): integrate lock_ref_sha1_basic() errors into ours lock_ref_sha1_basic(): improve diagnostics for ref D/F conflicts lock_ref_sha1_basic(): report errors via a "struct strbuf *err" verify_refname_available(): report errors via a "struct strbuf *err" verify_refname_available(): rename function refs: check for D/F conflicts among refs created in a transaction ref_transaction_commit(): use a string_list for detecting duplicates is_refname_available(): use dirname in first loop struct nonmatching_ref_data: store a refname instead of a ref_entry report_refname_conflict(): inline function entry_matches(): inline function is_refname_available(): convert local variable "dirname" to strbuf is_refname_available(): avoid shadowing "dir" variable is_refname_available(): revamp the comments t1404: new tests of ref D/F conflicts within transactions
| * | reflog_expire(): integrate lock_ref_sha1_basic() errors into oursmh/ref-directory-file-3mh/ref-directory-fileMichael Haggerty2015-05-111-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | Now that lock_ref_sha1_basic() gives us back its error messages via a strbuf, incorporate its error message into our error message rather than emitting two separate error messages. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | ref_transaction_commit(): delete extra "the" from error messageMichael Haggerty2015-05-111-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | While we are in the area, let's remove a superfluous definite article from the error message that is emitted when the reference cannot be locked. This improves how it reads and makes it a bit shorter. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | ref_transaction_commit(): provide better error messagesMichael Haggerty2015-05-111-4/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | Now that lock_ref_sha1_basic() gives us back its error messages via a strbuf, incorporate its error message into our error message rather than emitting one error messages to stderr immediately and returning a second to our caller. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | rename_ref(): integrate lock_ref_sha1_basic() errors into oursMichael Haggerty2015-05-111-4/+2
| | | | | | | | | | | | | | | | | | | | | | | | Now that lock_ref_sha1_basic() gives us back its error messages via a strbuf, incorporate its error message into our error message rather than emitting two separate error messages. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | lock_ref_sha1_basic(): improve diagnostics for ref D/F conflictsMichael Haggerty2015-05-111-4/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If there is a failure to lock a reference that is likely caused by a D/F conflict (e.g., trying to lock "refs/foo/bar" when reference "refs/foo" already exists), invoke verify_refname_available() to try to generate a more helpful error message. That function might not detect an error. For example, some non-reference file might be blocking the deletion of an otherwise-empty directory tree, or there might be a race with another process that just deleted the offending reference. In such cases, generate the strerror-based error message like before. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | lock_ref_sha1_basic(): report errors via a "struct strbuf *err"Michael Haggerty2015-05-111-16/+28
| | | | | | | | | | | | | | | | | | | | | | | | For now, change the callers to spew the error to stderr like before. But soon we will change them to incorporate the reason for the failure into their own error messages. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | verify_refname_available(): report errors via a "struct strbuf *err"Michael Haggerty2015-05-111-20/+30
| | | | | | | | | | | | | | | | | | | | | | | | It shouldn't be spewing errors directly to stderr. For now, change its callers to spew the errors to stderr. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | verify_refname_available(): rename functionMichael Haggerty2015-05-111-17/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | Rename is_refname_available() to verify_refname_available() and change its return value from 1 for success to 0 for success, to be consistent with our error-handling convention. In a moment it will also get a "struct strbuf *err" parameter. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | refs: check for D/F conflicts among refs created in a transactionMichael Haggerty2015-05-111-62/+94
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If two references that D/F conflict (e.g., "refs/foo" and "refs/foo/bar") are created in a single transaction, the old code discovered the problem only after the "commit" phase of ref_transaction_commit() had already begun. This could leave some references updated and others not, which violates the promise of atomicity. Instead, check for such conflicts during the "locking" phase: * Teach is_refname_available() to take an "extras" parameter that can contain extra reference names with which the specified refname must not conflict. * Change lock_ref_sha1_basic() to take an "extras" parameter, which it passes through to is_refname_available(). * Change ref_transaction_commit() to pass "affected_refnames" to lock_ref_sha1_basic() as its "extras" argument. This change fixes a test case in t1404. This code is a bit stricter than it needs to be. We could conceivably allow reference "refs/foo/bar" to be created in the same transaction as "refs/foo" is deleted (or vice versa). But that would be complicated to implement, because it is not possible to lock "refs/foo/bar" while "refs/foo" exists as a loose reference, but on the other hand we don't want to delete some references before adding others (because that could leave a gap during which required objects are unreachable). There is also a complication that reflog files' paths can conflict. Any less-strict implementation would probably require tricks like the packing of all references before the start of the real transaction, or the use of temporary intermediate reference names. So for now let's accept too-strict checks. Some reference update transactions will be rejected unnecessarily, but they will be rejected in their entirety rather than leaving the repository in an intermediate state, as would happen now. Please note that there is still one kind of D/F conflict that is *not* handled correctly. If two processes are running at the same time, and one tries to create "refs/foo" at the same time that the other tries to create "refs/foo/bar", then they can race with each other. Both processes can obtain their respective locks ("refs/foo.lock" and "refs/foo/bar.lock"), proceed to the "commit" phase of ref_transaction_commit(), and then the slower process will discover that it cannot rename its lockfile into place (after possibly having committed changes to other references). There appears to be no way to fix this race without changing the locking policy, which in turn would require a change to *all* Git clients. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | ref_transaction_commit(): use a string_list for detecting duplicatesMichael Haggerty2015-05-111-14/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Detect duplicates by storing the reference names in a string_list and sorting that, instead of sorting the ref_updates directly. * In a moment the string_list will be used for another purpose, too. * This removes the need for the custom comparison function ref_update_compare(). * This means that we can carry out the updates in the order that the user specified them instead of reordering them. This might be handy someday if, we want to permit multiple updates to a single reference as long as they are compatible with each other. Note: we can't use string_list_remove_duplicates() to check for duplicates, because we need to know the name of the reference that appeared multiple times, to be used in the error message. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | is_refname_available(): use dirname in first loopMichael Haggerty2015-05-111-14/+26
| | | | | | | | | | | | | | | | | | | | | | | | | | | In the first loop (over prefixes of refname), use dirname to keep track of the current prefix. This is not an improvement in itself, but in a moment we will start using dirname for a role where a NUL-terminated string is needed. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | struct nonmatching_ref_data: store a refname instead of a ref_entryMichael Haggerty2015-05-111-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | Now that we don't need a ref_entry to pass to report_refname_conflict(), it is sufficient to store the refname of the conflicting reference. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | report_refname_conflict(): inline functionMichael Haggerty2015-05-111-8/+2
| | | | | | | | | | | | | | | | | | | | | | | | It wasn't pulling its weight. And we are about to need code similar to this where no ref_entry is available and with more diverse error messages. Rather than try to generalize the function, just inline it. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | entry_matches(): inline functionMichael Haggerty2015-05-111-7/+2
| | | | | | | | | | | | | | | | | | | | | | | | It wasn't pulling its weight. And in a moment we will need similar tests that take a refname rather than a ref_entry as parameter, which would have made entry_matches() even less useful. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | is_refname_available(): convert local variable "dirname" to strbufMichael Haggerty2015-05-111-7/+5
| | | | | | | | | | | | | | | | | | | | | This change wouldn't be worth it by itself, but in a moment we will use the strbuf for more string juggling. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | is_refname_available(): avoid shadowing "dir" variableMichael Haggerty2015-05-111-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | The function had a "dir" parameter that was shadowed by a local "dir" variable within a code block. Use the former in place of the latter. (This is consistent with "dir"'s use elsewhere in the function.) Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
| * | is_refname_available(): revamp the commentsMichael Haggerty2015-05-111-22/+47
| | | | | | | | | | | | | | | | | | | | | Change the comments to a running example of running the function with refname set to "refs/foo/bar". Add some more explanation of the logic. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
* | | Merge branch 'mh/write-refs-sooner-2.4'Junio C Hamano2015-05-221-31/+82
|\ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Multi-ref transaction support we merged a few releases ago unnecessarily kept many file descriptors open, risking to fail with resource exhaustion. This is for 2.4.x track. * mh/write-refs-sooner-2.4: ref_transaction_commit(): fix atomicity and avoid fd exhaustion ref_transaction_commit(): remove the local flags variable ref_transaction_commit(): inline call to write_ref_sha1() rename_ref(): inline calls to write_ref_sha1() from this function commit_ref_update(): new function, extracted from write_ref_sha1() write_ref_to_lockfile(): new function, extracted from write_ref_sha1() t7004: rename ULIMIT test prerequisite to ULIMIT_STACK_SIZE update-ref: test handling large transactions properly ref_transaction_commit(): fix atomicity and avoid fd exhaustion ref_transaction_commit(): remove the local flags variable ref_transaction_commit(): inline call to write_ref_sha1() rename_ref(): inline calls to write_ref_sha1() from this function commit_ref_update(): new function, extracted from write_ref_sha1() write_ref_to_lockfile(): new function, extracted from write_ref_sha1() t7004: rename ULIMIT test prerequisite to ULIMIT_STACK_SIZE update-ref: test handling large transactions properly
| * | | ref_transaction_commit(): fix atomicity and avoid fd exhaustionMichael Haggerty2015-05-121-21/+53
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The old code was roughly for update in updates: acquire locks and check old_sha for update in updates: if changing value: write_ref_to_lockfile() commit_ref_update() for update in updates: if deleting value: unlink() rewrite packed-refs file for update in updates: if reference still locked: unlock_ref() This has two problems. Non-atomic updates ================== The atomicity of the reference transaction depends on all pre-checks being done in the first loop, before any changes have started being committed in the second loop. The problem is that write_ref_to_lockfile() (previously part of write_ref_sha1()), which is called from the second loop, contains two more checks: * It verifies that new_sha1 is a valid object * If the reference being updated is a branch, it verifies that new_sha1 points at a commit object (as opposed to a tag, tree, or blob). If either of these checks fails, the "transaction" is aborted during the second loop. But this might happen after some reference updates have already been permanently committed. In other words, the all-or-nothing promise of "git update-ref --stdin" could be violated. So these checks have to be moved to the first loop. File descriptor exhaustion ========================== The old code locked all of the references in the first loop, leaving all of the lockfiles open until later loops. Since we might be updating a lot of references, this could result in file descriptor exhaustion. The solution ============ After this patch, the code looks like for update in updates: acquire locks and check old_sha if changing value: write_ref_to_lockfile() else: close_ref() for update in updates: if changing value: commit_ref_update() for update in updates: if deleting value: unlink() rewrite packed-refs file for update in updates: if reference still locked: unlock_ref() This fixes both problems: 1. The pre-checks in write_ref_to_lockfile() are now done in the first loop, before any changes have been committed. If any of the checks fails, the whole transaction can now be rolled back correctly. 2. All lockfiles are closed in the first loop immediately after they are created (either by write_ref_to_lockfile() or by close_ref()). This means that there is never more than one open lockfile at a time, preventing file descriptor exhaustion. To simplify the bookkeeping across loops, add a new REF_NEEDS_COMMIT bit to update->flags, which keeps track of whether the corresponding lockfile needs to be committed, as opposed to just unlocked. (Since "struct ref_update" is internal to the refs module, this change is not visible to external callers.) This change fixes two tests in t1400. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | ref_transaction_commit(): remove the local flags variableMichael Haggerty2015-05-121-9/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Instead, work directly with update->flags. This has the advantage that the REF_DELETING bit, set in the first loop, can be read in the second loop instead of having to be recomputed. Plus, it was potentially confusing having both update->flags and flags, which sometimes had different values. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | ref_transaction_commit(): inline call to write_ref_sha1()Michael Haggerty2015-05-121-18/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | That was the last caller, so delete function write_ref_sha1(). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | rename_ref(): inline calls to write_ref_sha1() from this functionMichael Haggerty2015-05-121-4/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Most of what it does is unneeded from these call sites. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | commit_ref_update(): new function, extracted from write_ref_sha1()Michael Haggerty2015-05-121-7/+20
| | | | | | | | | | | | | | | | | | | | Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | write_ref_to_lockfile(): new function, extracted from write_ref_sha1()Michael Haggerty2015-05-121-4/+17
| |/ / | | | | | | | | | | | | | | | | | | | | | This is the first step towards separating the checking and writing of the new reference value to committing the change. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | | Merge branch 'sb/ref-lock-lose-lock-fd'Junio C Hamano2015-05-191-10/+5
|\ \ \ | |_|/ |/| | | | | | | | | | | | | | | | | | | | The refs API uses ref_lock struct which had its own "int fd", even though the same file descriptor was in the lock struct it contains. Clean-up the code to lose this redundant field. * sb/ref-lock-lose-lock-fd: refs.c: remove lock_fd from struct ref_lock
| * | refs.c: remove lock_fd from struct ref_locksb/ref-lock-lose-lock-fdStefan Beller2015-05-101-10/+5
| |/ | | | | | | | | | | | | | | | | | | | | The 'lock_fd' is the same as 'lk->fd'. No need to store it twice so remove it. No functional changes intended. Signed-off-by: Stefan Beller <sbeller@google.com> Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | Merge branch 'jk/reading-packed-refs'Junio C Hamano2015-05-111-2/+4
|\ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | An earlier rewrite to use strbuf_getwholeline() instead of fgets(3) to read packed-refs file revealed that the former is unacceptably inefficient. * jk/reading-packed-refs: t1430: add another refs-escape test read_packed_refs: avoid double-checking sane refs strbuf_getwholeline: use getdelim if it is available strbuf_getwholeline: avoid calling strbuf_grow strbuf_addch: avoid calling strbuf_grow config: use getc_unlocked when reading from file strbuf_getwholeline: use getc_unlocked git-compat-util: add fallbacks for unlocked stdio strbuf_getwholeline: use getc macro
| * | read_packed_refs: avoid double-checking sane refsJeff King2015-04-161-2/+4
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Prior to d0f810f (refs.c: allow listing and deleting badly named refs, 2014-09-03), read_packed_refs would barf on any malformed refnames by virtue of calling create_ref_entry with the "check" parameter set to 1. That commit loosened our reading so that we call check_refname_format ourselves and just set a REF_BAD_NAME flag. We then call create_ref_entry with the check parameter set to 0. That function learned to do an extra safety check even when the check parameter is 0, so that we don't load any dangerous refnames (like "../../../etc/passwd"). This is implemented by calling refname_is_safe() in create_ref_entry(). However, we can observe that refname_is_safe() can only be true if check_refname_format() also failed. So in the common case of a sanely named ref, we perform _both_ checks, even though we know that the latter will never trigger. This has a noticeable performance impact when the packed-refs file is large. Let's drop the refname_is_safe check from create_ref_entry(), and make it the responsibility of the caller. Of the three callers that pass a check parameter of "0", two will have just called check_refname_format(), and can check the refname-safety only when it fails. The third case, pack_if_possible_fn, is copying from an existing ref entry, which must have previously passed our safety check. With this patch, running "git rev-parse refs/heads/does-not-exist" on a repo with a large (1.6GB) packed-refs file went from: real 0m6.768s user 0m6.340s sys 0m0.432s to: real 0m5.703s user 0m5.276s sys 0m0.432s for a wall-clock speedup of 15%. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | Merge branch 'nd/multiple-work-trees'Junio C Hamano2015-05-111-13/+46
|\ \ | |/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A replacement for contrib/workdir/git-new-workdir that does not rely on symbolic links and make sharing of objects and refs safer by making the borrowee and borrowers aware of each other. * nd/multiple-work-trees: (41 commits) prune --worktrees: fix expire vs worktree existence condition t1501: fix test with split index t2026: fix broken &&-chain t2026 needs procondition SANITY git-checkout.txt: a note about multiple checkout support for submodules checkout: add --ignore-other-wortrees checkout: pass whole struct to parse_branchname_arg instead of individual flags git-common-dir: make "modules/" per-working-directory directory checkout: do not fail if target is an empty directory t2025: add a test to make sure grafts is working from a linked checkout checkout: don't require a work tree when checking out into a new one git_path(): keep "info/sparse-checkout" per work-tree count-objects: report unused files in $GIT_DIR/worktrees/... gc: support prune --worktrees gc: factor out gc.pruneexpire parsing code gc: style change -- no SP before closing parenthesis checkout: clean up half-prepared directories in --to mode checkout: reject if the branch is already checked out elsewhere prune: strategies for linked checkouts checkout: support checking out into a new working directory ...
| * git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy2014-12-011-9/+42
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In the previous patch, git_snpath() is modified to allocate a new strbuf buffer because vsnpath() needs that. But that makes it awkward because git_snpath() receives a pre-allocated buffer from outside and has to copy data back. Rename it to strbuf_git_path() and make it receive strbuf directly. Using git_path() in update_refs_for_switch() which used to call git_snpath() is safe because that function and all of its callers do not keep any pointer to the round-robin buffer pool allocated by get_pathname(). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy2014-12-011-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Before the previous commit, get_pathname returns an array of PATH_MAX length. Even if git_path() and similar functions does not use the whole array, git_path() caller can, in theory. After the commit, get_pathname() may return a buffer that has just enough room for the returned string and git_path() caller should never write beyond that. Make git_path(), mkpath() and git_path_submodule() return a const buffer to make sure callers do not write in it at all. This could have been part of the previous commit, but the "const" conversion is too much distraction from the core changes in path.c. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | Merge branch 'jk/prune-with-corrupt-refs'Junio C Hamano2015-03-251-66/+6
|\ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "git prune" used to largely ignore broken refs when deciding which objects are still being used, which could spread an existing small damage and make it a larger one. * jk/prune-with-corrupt-refs: refs.c: drop curate_packed_refs repack: turn on "ref paranoia" when doing a destructive repack prune: turn on ref_paranoia flag refs: introduce a "ref paranoia" flag t5312: test object deletion code paths in a corrupted repository
| * | refs.c: drop curate_packed_refsjk/prune-with-corrupt-refsJeff King2015-03-201-66/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When we delete a ref, we have to rewrite the entire packed-refs file. We take this opportunity to "curate" the packed-refs file and drop any entries that are crufty or broken. Dropping broken entries (e.g., with bogus names, or ones that point to missing objects) is actively a bad idea, as it means that we lose any notion that the data was there in the first place. Aside from the general hackiness that we might lose any information about ref "foo" while deleting an unrelated ref "bar", this may seriously hamper any attempts by the user at recovering from the corruption in "foo". They will lose the sha1 and name of "foo"; the exact pointer may still be useful even if they recover missing objects from a different copy of the repository. But worse, once the ref is gone, there is no trace of the corruption. A follow-up "git prune" may delete objects, even though it would otherwise bail when seeing corruption. We could just drop the "broken" bits from curate_packed_refs, and continue to drop the "crufty" bits: refs whose loose counterpart exists in the filesystem. This is not wrong to do, and it does have the advantage that we may write out a slightly smaller packed-refs file. But it has two disadvantages: 1. It is a potential source of races or mistakes with respect to these refs that are otherwise unrelated to the operation. To my knowledge, there aren't any active problems in this area, but it seems like an unnecessary risk. 2. We have to spend time looking up the matching loose refs for every item in the packed-refs file. If you have a large number of packed refs that do not change, that outweighs the benefit from writing out a smaller packed-refs file (it doesn't get smaller, and you do a bunch of directory traversal to find that out). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | refs: introduce a "ref paranoia" flagJeff King2015-03-201-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Most operations that iterate over refs are happy to ignore broken cruft. However, some operations should be performed with knowledge of these broken refs, because it is better for the operation to choke on a missing object than it is to silently pretend that the ref did not exist (e.g., if we are computing the set of reachable tips in order to prune objects). These processes could just call for_each_rawref, except that ref iteration is often hidden behind other interfaces. For instance, for a destructive "repack -ad", we would have to inform "pack-objects" that we are destructive, and then it would in turn have to tell the revision code that our "--all" should include broken refs. It's much simpler to just set a global for "dangerous" operations that includes broken refs in all iterations. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | Merge branch 'jk/blame-commit-label' into maintJunio C Hamano2015-02-241-2/+1
| |\ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "git blame HEAD -- missing" failed to correctly say "HEAD" when it tried to say "No such path 'missing' in HEAD". * jk/blame-commit-label: blame.c: fix garbled error message use xstrdup_or_null to replace ternary conditionals builtin/commit.c: use xstrdup_or_null instead of envdup builtin/apply.c: use xstrdup_or_null instead of null_strdup git-compat-util: add xstrdup_or_null helper
* | \ \ Merge branch 'mh/expire-updateref-fixes'Junio C Hamano2015-03-101-28/+37
|\ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Various issues around "reflog expire", e.g. using --updateref when expiring a reflog for a symbolic reference, have been corrected and/or made saner. * mh/expire-updateref-fixes: reflog_expire(): never update a reference to null_sha1 reflog_expire(): ignore --updateref for symbolic references reflog: improve and update documentation struct ref_lock: delete the force_write member lock_ref_sha1_basic(): do not set force_write for missing references write_ref_sha1(): move write elision test to callers write_ref_sha1(): remove check for lock == NULL
| * | | | reflog_expire(): never update a reference to null_sha1mh/expire-updateref-fixesMichael Haggerty2015-03-051-2/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, if --updateref is specified and the very last reflog entry is expired or deleted, the reference's value is set to 0{40}. This is an invalid state of the repository, and breaks, for example, "git fsck" and "git for-each-ref". The only place we use --updateref in our own code is when dropping stash entries. In that code, the very next step is to check if the reflog has been made empty, and if so, delete the "refs/stash" reference entirely. Thus that code path ultimately leaves the repository in a valid state. But we don't want to the repository in an invalid state even temporarily, and we don't want to leave an invalid state if other callers of "git reflog expire|delete --updateref" don't think to do the extra cleanup step. So, if "git reflog expire|delete" leaves no more entries in the reflog, just leave the reference unchanged. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | reflog_expire(): ignore --updateref for symbolic referencesMichael Haggerty2015-03-051-3/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we are expiring reflog entries for a symbolic reference, then how should --updateref be handled if the newest reflog entry is expired? Option 1: Update the referred-to reference. (This is what the current code does.) This doesn't make sense, because the referred-to reference has its own reflog, which hasn't been rewritten. Option 2: Update the symbolic reference itself (as in, REF_NODEREF). This would convert the symbolic reference into a non-symbolic reference (e.g., detaching HEAD), which is surely not what a user would expect. Option 3: Error out. This is plausible, but it would make the following usage impossible: git reflog expire ... --updateref --all Option 4: Ignore --updateref for symbolic references. We choose to implement option 4. Note: another problem in this code will be fixed in a moment. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | struct ref_lock: delete the force_write memberStefan Beller2015-03-051-5/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Instead, compute the value when it is needed. Signed-off-by: Stefan Beller <sbeller@google.com> Edited-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | lock_ref_sha1_basic(): do not set force_write for missing referencesMichael Haggerty2015-03-051-9/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If a reference is missing, its SHA-1 will be null_sha1, which can't possibly match a new value that ref_transaction_commit() is trying to update it to. So there is no need to set force_write in this scenario. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | write_ref_sha1(): move write elision test to callersMichael Haggerty2015-03-051-9/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | write_ref_sha1() previously skipped the write if the reference already had the desired value, unless lock->force_write was set. Instead, perform that test at the callers. Two of the callers (in rename_ref()) unconditionally set force_write just before calling write_ref_sha1(), so they don't need the extra check at all. Nor do they need to set force_write anymore. The last caller, in ref_transaction_commit(), still needs the test. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | write_ref_sha1(): remove check for lock == NULLMichael Haggerty2015-03-051-4/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | None of the callers pass NULL to this function, and there doesn't seem to be any usefulness to allowing them to do so. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
| * | | | Merge branch 'mh/reflog-expire' into mh/ref-trans-value-checkJunio C Hamano2015-02-091-82/+181
| |\ \ \ \ | | |/ / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * mh/reflog-expire: (24 commits) refs.c: let fprintf handle the formatting refs.c: don't expose the internal struct ref_lock in the header file lock_any_ref_for_update(): inline function refs.c: remove unlock_ref/close_ref/commit_ref from the refs api reflog_expire(): new function in the reference API expire_reflog(): treat the policy callback data as opaque Move newlog and last_kept_sha1 to "struct expire_reflog_cb" expire_reflog(): move rewrite to flags argument expire_reflog(): move verbose to flags argument expire_reflog(): pass flags through to expire_reflog_ent() struct expire_reflog_cb: a new callback data type Rename expire_reflog_cb to expire_reflog_policy_cb expire_reflog(): move updateref to flags argument expire_reflog(): move dry_run to flags argument expire_reflog(): add a "flags" argument expire_reflog(): extract two policy-related functions Extract function should_expire_reflog_ent() expire_reflog(): use a lock_file for rewriting the reflog file expire_reflog(): return early if the reference has no reflog expire_reflog(): rename "ref" parameter to "refname" ...
* | | | | update_ref(): improve documentationMichael Haggerty2015-02-171-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add a docstring for update_ref(), emphasizing its similarity to ref_transaction_update(). Rename its parameters to match those of ref_transaction_update(). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | | | | ref_transaction_verify(): new function to check a reference's valueMichael Haggerty2015-02-171-8/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If NULL is passed to ref_transaction_update()'s new_sha1 parameter, then just verify old_sha1 (under lock) without trying to change the new value of the reference. Use this functionality to add a new function ref_transaction_verify(), which checks the current value of the reference under lock but doesn't change it. Use ref_transaction_verify() in the implementation of "git update-ref --stdin"'s "verify" command to avoid the awkward need to "update" the reference to its existing value. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | | | | ref_transaction_delete(): check that old_sha1 is not null_sha1Michael Haggerty2015-02-171-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | It makes no sense to delete a reference that is already known not to exist. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
* | | | | ref_transaction_create(): check that new_sha1 is validMichael Haggerty2015-02-171-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Creating a reference requires a new_sha1 that is not NULL and not null_sha1. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>