diff options
140 files changed, 2459 insertions, 1180 deletions
diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.txt index 541815ee34..248ba70c3d 100644 --- a/Documentation/RelNotes/2.15.0.txt +++ b/Documentation/RelNotes/2.15.0.txt @@ -488,6 +488,10 @@ Fixes since v2.14 described in an earlier part of the doc. (merge 07c4984508 dg/filter-branch-filter-order-doc later to maint). + * A possible oom error is now caught as a fatal error, instead of + continuing and dereferencing NULL. + (merge 55d7d15847 ao/path-use-xmalloc later to maint). + * Other minor doc, test and build updates and code cleanups. (merge f094b89a4d ma/parse-maybe-bool later to maint). (merge 6cdf8a7929 ma/ts-cleanups later to maint). @@ -499,3 +503,6 @@ Fixes since v2.14 (merge 7cbbf9d6a2 ls/filter-process-delayed later to maint). (merge 488aa65c8f wk/merge-options-gpg-sign-doc later to maint). (merge e61cb19a27 jc/branch-force-doc-readability-fix later to maint). + (merge 32fceba3fd np/config-path-doc later to maint). + (merge e38c681fb7 sb/rev-parse-show-superproject-root later to maint). + (merge 4f851dc883 sg/rev-list-doc-reorder-fix later to maint). diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.txt new file mode 100644 index 0000000000..f1dd8c8626 --- /dev/null +++ b/Documentation/RelNotes/2.16.0.txt @@ -0,0 +1,84 @@ +Git 2.16 Release Notes +====================== + +Backward compatibility notes and other notable changes. + + * Use of an empty string as a pathspec element that is used for + 'everything matches' is now an error. + + +Updates since v2.15 +------------------- + +UI, Workflows & Features + + * An empty string as a pathspec element that means "everything" + i.e. 'git add ""', is now illegal. We started this by first + deprecating and warning a pathspec that has such an element in + 2.11 (Nov 2016). + + +Performance, Internal Implementation, Development Support etc. + + * An earlier update made it possible to use an on-stack in-core + lockfile structure (as opposed to having to deliberately leak an + on-heap one). Many codepaths have been updated to take advantage + of this new facility. + (merge b74c90fb41 ma/lockfile-fixes later to maint). + + * Calling cmd_foo() as if it is a general purpose helper function is + a no-no. Correct two instances of such to set an example. + (merge a92b1095d1 jc/no-cmd-as-subroutine later to maint). + + * We try to see if somebody runs our test suite with a shell that + does not support "local" like bash/dash does. + (merge 01d3a526ad mh/test-local-canary later to maint). + + +Also contains various documentation updates and code clean-ups. + + +Fixes since v2.15 +----------------- + + * "auto" as a value for the columnar output configuration ought to + judge "is the output consumed by humans?" with the same criteria as + "auto" for coloured output configuration, i.e. either the standard + output stream is going to tty, or a pager is in use. We forgot the + latter, which has been fixed. + (merge 965ff23a43 kd/auto-col-with-pager-fix later to maint). + + * The experimental "color moved lines differently in diff output" + feature was buggy around "ignore whitespace changes" edges, whihch + has been corrected. + (merge b66b507292 jk/diff-color-moved-fix later to maint). + + * Instead of using custom line comparison and hashing functions to + implement "moved lines" coloring in the diff output, use the pair + of these functions from lower-layer xdiff/ code. + (merge 01be97c2b2 sb/diff-color-moved-use-xdl-recmatch later to maint). + + * Some codepaths did not check for errors when asking what branch the + HEAD points at, which have been fixed. + (merge dbd2b55cb7 jk/misc-resolve-ref-unsafe-fixes later to maint). + + * "git commit", after making a commit, did not check for errors when + asking on what branch it made the commit, which has been correted. + (merge c26de08370 ao/check-resolve-ref-unsafe-result later to maint). + + * "git status --ignored -u" did not stop at a working tree of a + separate project that is embedded in an ignored directory and + listed files in that other project, instead of just showing the + directory itself as ignored. + (merge fadb4820c4 js/submodule-in-excluded later to maint). + + * A broken access to object databases in recent update to "git grep + --recurse-submodules" has been fixed. + (merge 9560e6245a bw/grep-recurse-submodules later to maint). + + * A recent regression in "git rebase -i" that broke execution of git + commands from subdirectories via "exec" insn has been fixed. + (merge 09d7b6c6fa jk/rebase-i-exec-gitdir-fix later to maint). + + * Other minor doc, test and build updates and code cleanups. + (merge bab76141da cn/diff-indent-no-longer-is-experimental later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 1ac0ae6adb..5f0d62753d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -351,6 +351,9 @@ advice.*:: addEmbeddedRepo:: Advice on what to do when you've accidentally added one git repo inside of another. + ignoredHook:: + Advice shown if an hook is ignored because the hook is not + set as executable. -- core.fileMode:: @@ -2621,6 +2624,35 @@ push.gpgSign:: override a value from a lower-priority config file. An explicit command-line flag always overrides this config option. +push.pushOption:: + When no `--push-option=<option>` argument is given from the + command line, `git push` behaves as if each <value> of + this variable is given as `--push-option=<value>`. ++ +This is a multi-valued variable, and an empty value can be used in a +higher priority configuration file (e.g. `.git/config` in a +repository) to clear the values inherited from a lower priority +configuration files (e.g. `$HOME/.gitconfig`). ++ +-- + +Example: + +/etc/gitconfig + push.pushoption = a + push.pushoption = b + +~/.gitconfig + push.pushoption = c + +repo/.git/config + push.pushoption = + push.pushoption = b + +This will result in only b (a and c are cleared). + +-- + push.recurseSubmodules:: Make sure all submodule commits used by the revisions to be pushed are available on a remote-tracking branch. If the value is 'check' diff --git a/Documentation/diff-heuristic-options.txt b/Documentation/diff-heuristic-options.txt deleted file mode 100644 index d4f3d95505..0000000000 --- a/Documentation/diff-heuristic-options.txt +++ /dev/null @@ -1,5 +0,0 @@ ---indent-heuristic:: ---no-indent-heuristic:: - These are to help debugging and tuning experimental heuristics - (which are off by default) that shift diff hunk boundaries to - make patches easier to read. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index a88c76741e..dd0dba5b1d 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -63,7 +63,12 @@ ifndef::git-format-patch[] Synonym for `-p --raw`. endif::git-format-patch[] -include::diff-heuristic-options.txt[] +--indent-heuristic:: + Enable the heuristic that shift diff hunk boundaries to make patches + easier to read. This is the default. + +--no-indent-heuristic:: + Disable the indent heuristic. --minimal:: Spend extra time to make sure the smallest possible diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt index 94be4b85e0..05fd482b74 100644 --- a/Documentation/git-annotate.txt +++ b/Documentation/git-annotate.txt @@ -23,7 +23,6 @@ familiar command name for people coming from other SCM systems. OPTIONS ------- include::blame-options.txt[] -include::diff-heuristic-options.txt[] SEE ALSO -------- diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index fdc3aea30a..16323eb80e 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -89,8 +89,6 @@ include::blame-options.txt[] abbreviated object name, use <n>+1 digits. Note that 1 column is used for a caret to mark the boundary commit. -include::diff-heuristic-options.txt[] - THE PORCELAIN FORMAT -------------------- diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 92777cef25..cf0a0b7df2 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -77,7 +77,14 @@ reference name expressions (see linkgit:gitrevisions[7]): . at-open-brace `@{` is used as a notation to access a reflog entry. -With the `--branch` option, it expands the ``previous branch syntax'' +With the `--branch` option, the command takes a name and checks if +it can be used as a valid branch name (e.g. when creating a new +branch). The rule `git check-ref-format --branch $name` implements +may be stricter than what `git check-ref-format refs/heads/$name` +says (e.g. a dash may appear at the beginning of a ref component, +but it is explicitly forbidden at the beginning of a branch name). +When run with `--branch` option in a repository, the input is first +expanded for the ``previous branch syntax'' `@{-n}`. For example, `@{-1}` is a way to refer the last branch you were on. This option should be used by porcelains to accept this syntax anywhere a branch name is expected, so they can act as if you diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 83f86b9231..4edd09fc6b 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -174,11 +174,11 @@ See also <<FILES>>. either --bool or --int, as described above. --path:: - 'git-config' will expand leading '{tilde}' to the value of - '$HOME', and '{tilde}user' to the home directory for the + `git config` will expand a leading `~` to the value of + `$HOME`, and `~user` to the home directory for the specified user. This option has no effect when setting the - value (but you can use 'git config bla {tilde}/' from the - command line to let your shell do the expansion). + value (but you can use `git config section.variable ~/` + from the command line to let your shell do the expansion). -z:: --null:: diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 3c6927b1fb..d5dfd8430f 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -64,14 +64,6 @@ OPTIONS ------- include::merge-options.txt[] ---signoff:: - Add Signed-off-by line by the committer at the end of the commit - log message. The meaning of a signoff depends on the project, - but it typically certifies that committer has - the rights to submit this work under the same license and - agrees to a Developer Certificate of Origin - (see http://developercertificate.org/ for more information). - -m <msg>:: Set the commit message to be used for the merge commit (in case one is created). diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 3e76e99f38..5b08302fc2 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -156,11 +156,17 @@ already exists on the remote side. Either all refs are updated, or on error, no refs are updated. If the server does not support atomic pushes the push will fail. --o:: ---push-option:: +-o <option>:: +--push-option=<option>:: Transmit the given string to the server, which passes them to the pre-receive as well as the post-receive hook. The given string must not contain a NUL or LF character. + When multiple `--push-option=<option>` are given, they are + all sent to the other side in the order listed on the + command line. + When no `--push-option=<option>` is given from the command + line, the values of configuration variable `push.pushOption` + are used instead. --receive-pack=<git-receive-pack>:: --exec=<git-receive-pack>:: diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 0917b8207b..95326b85ff 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -264,7 +264,7 @@ print a message to stderr and exit with nonzero status. --show-toplevel:: Show the absolute path of the top-level directory. ---show-superproject-working-tree +--show-superproject-working-tree:: Show the absolute path of the root of the superproject's working tree (if exists) that uses the current repository as its submodule. Outputs nothing if the current repository is diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index 2552ab8e8d..3888c3ff85 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -57,6 +57,16 @@ set to `no` at the beginning of them. With --no-log do not list one-line descriptions from the actual commits being merged. +--signoff:: +--no-signoff:: + Add Signed-off-by line by the committer at the end of the commit + log message. The meaning of a signoff depends on the project, + but it typically certifies that committer has + the rights to submit this work under the same license and + agrees to a Developer Certificate of Origin + (see http://developercertificate.org/ for more information). ++ +With --no-signoff do not add a Signed-off-by line. --stat:: -n:: diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 7d860bfca1..13501e1556 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -799,11 +799,11 @@ endif::git-rev-list[] --parents:: Print also the parents of the commit (in the form "commit parent..."). - Also enables parent rewriting, see 'History Simplification' below. + Also enables parent rewriting, see 'History Simplification' above. --children:: Print also the children of the commit (in the form "commit child..."). - Also enables parent rewriting, see 'History Simplification' below. + Also enables parent rewriting, see 'History Simplification' above. ifdef::git-rev-list[] --timestamp:: @@ -846,7 +846,7 @@ you would get an output like this: to be drawn properly. Cannot be combined with `--no-walk`. + -This enables parent rewriting, see 'History Simplification' below. +This enables parent rewriting, see 'History Simplification' above. + This implies the `--topo-order` option by default, but the `--date-order` option may also be specified. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 9ef24f24d8..a9dbc3f12c 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.15.0-rc2 +DEF_VER=v2.15.0 LF=' ' @@ -1 +1 @@ -Documentation/RelNotes/2.15.0.txt
\ No newline at end of file +Documentation/RelNotes/2.16.0.txt
\ No newline at end of file @@ -17,6 +17,7 @@ int advice_set_upstream_failure = 1; int advice_object_name_warning = 1; int advice_rm_hints = 1; int advice_add_embedded_repo = 1; +int advice_ignored_hook = 1; static struct { const char *name; @@ -38,6 +39,7 @@ static struct { { "objectnamewarning", &advice_object_name_warning }, { "rmhints", &advice_rm_hints }, { "addembeddedrepo", &advice_add_embedded_repo }, + { "ignoredhook", &advice_ignored_hook }, /* make this an alias for backward compatibility */ { "pushnonfastforward", &advice_push_update_rejected } @@ -19,6 +19,7 @@ extern int advice_set_upstream_failure; extern int advice_object_name_warning; extern int advice_rm_hints; extern int advice_add_embedded_repo; +extern int advice_ignored_hook; int git_default_advice_config(const char *var, const char *value); __attribute__((format (printf, 1, 2))) @@ -75,13 +75,10 @@ static int parse_ignorewhitespace_option(struct apply_state *state, } int init_apply_state(struct apply_state *state, - const char *prefix, - struct lock_file *lock_file) + const char *prefix) { memset(state, 0, sizeof(*state)); state->prefix = prefix; - state->lock_file = lock_file; - state->newfd = -1; state->apply = 1; state->line_termination = '\n'; state->p_value = 1; @@ -146,8 +143,6 @@ int check_apply_state(struct apply_state *state, int force_apply) } if (state->check_index) state->unsafe_paths = 0; - if (!state->lock_file) - return error("BUG: state->lock_file should not be NULL"); if (state->apply_verbosity <= verbosity_silent) { state->saved_error_routine = get_error_routine(); @@ -4709,13 +4704,13 @@ static int apply_patch(struct apply_state *state, state->apply = 0; state->update_index = state->check_index && state->apply; - if (state->update_index && state->newfd < 0) { + if (state->update_index && !is_lock_file_locked(&state->lock_file)) { if (state->index_file) - state->newfd = hold_lock_file_for_update(state->lock_file, - state->index_file, - LOCK_DIE_ON_ERROR); + hold_lock_file_for_update(&state->lock_file, + state->index_file, + LOCK_DIE_ON_ERROR); else - state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR); } if (state->check_index && read_apply_cache(state) < 0) { @@ -4911,22 +4906,18 @@ int apply_all_patches(struct apply_state *state, } if (state->update_index) { - res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK); + res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK); if (res) { error(_("Unable to write new index file")); res = -128; goto end; } - state->newfd = -1; } res = !!errs; end: - if (state->newfd >= 0) { - rollback_lock_file(state->lock_file); - state->newfd = -1; - } + rollback_lock_file(&state->lock_file); if (state->apply_verbosity <= verbosity_silent) { set_error_routine(state->saved_error_routine); @@ -36,9 +36,8 @@ enum apply_verbosity { struct apply_state { const char *prefix; - /* These are lock_file related */ - struct lock_file *lock_file; - int newfd; + /* Lock file */ + struct lock_file lock_file; /* These control what gets looked at and modified */ int apply; /* this is not a dry-run */ @@ -116,8 +115,7 @@ extern int apply_parse_options(int argc, const char **argv, int *force_apply, int *options, const char * const *apply_usage); extern int init_apply_state(struct apply_state *state, - const char *prefix, - struct lock_file *lock_file); + const char *prefix); extern void clear_apply_state(struct apply_state *state); extern int check_apply_state(struct apply_state *state, int force_apply); @@ -371,7 +371,7 @@ static void parse_treeish_arg(const char **argv, const char *colon = strchrnul(name, ':'); int refnamelen = colon - name; - if (!dwim_ref(name, refnamelen, oid.hash, &ref)) + if (!dwim_ref(name, refnamelen, &oid, &ref)) die("no such ref: %.*s", refnamelen, name); free(ref); } @@ -433,7 +433,12 @@ static int read_bisect_refs(void) static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES") static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV") +static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK") +static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN") +static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START") +static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG") static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS") +static GIT_PATH_FUNC(git_path_head_name, "head-name") static void read_bisect_paths(struct argv_array *array) { @@ -685,11 +690,12 @@ static int bisect_checkout(const struct object_id *bisect_rev, int no_checkout) char bisect_rev_hex[GIT_MAX_HEXSZ + 1]; memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1); - update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR); argv_checkout[2] = bisect_rev_hex; if (no_checkout) { - update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0, + UPDATE_REFS_DIE_ON_ERR); } else { int res; res = run_command_v_opt(argv_checkout, RUN_GIT_CMD); @@ -1044,3 +1050,40 @@ int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } + +static int mark_for_removal(const char *refname, const struct object_id *oid, + int flag, void *cb_data) +{ + struct string_list *refs = cb_data; + char *ref = xstrfmt("refs/bisect%s", refname); + string_list_append(refs, ref); + return 0; +} + +int bisect_clean_state(void) +{ + int result = 0; + + /* There may be some refs packed during bisection */ + struct string_list refs_for_removal = STRING_LIST_INIT_NODUP; + for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal); + string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD")); + result = delete_refs("bisect: remove", &refs_for_removal, REF_NODEREF); + refs_for_removal.strdup_strings = 1; + string_list_clear(&refs_for_removal, 0); + unlink_or_warn(git_path_bisect_expected_rev()); + unlink_or_warn(git_path_bisect_ancestors_ok()); + unlink_or_warn(git_path_bisect_log()); + unlink_or_warn(git_path_bisect_names()); + unlink_or_warn(git_path_bisect_run()); + unlink_or_warn(git_path_bisect_terms()); + /* Cleanup head-name if it got left by an old version of git-bisect */ + unlink_or_warn(git_path_head_name()); + /* + * Cleanup BISECT_START last to support the --no-checkout option + * introduced in the commit 4796e823a. + */ + unlink_or_warn(git_path_bisect_start()); + + return result; +} @@ -28,4 +28,6 @@ extern int estimate_bisect_steps(int all); extern void read_bisect_terms(const char **bad, const char **good); +extern int bisect_clean_state(void); + #endif @@ -166,7 +166,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, commit->date = now; parent_tail = &commit->parents; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) die("no such ref: HEAD"); parent_tail = append_parent(parent_tail, &head_oid); @@ -1689,7 +1689,7 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs, return NULL; /* Do we have HEAD? */ - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return NULL; head_commit = lookup_commit_reference_gently(&head_oid, 1); if (!head_commit) @@ -264,7 +264,7 @@ void create_branch(const char *name, const char *start_name, die(_("Not a valid object name: '%s'."), start_name); } - switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) { + switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref)) { case 0: /* Not branching from any existing branch */ if (explicit_tracking) @@ -305,7 +305,7 @@ void create_branch(const char *name, const char *start_name, transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, - oid.hash, forcing ? NULL : null_sha1, + &oid, forcing ? NULL : &null_oid, 0, msg, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); diff --git a/builtin/am.c b/builtin/am.c index d7513f5375..4b6f1534f8 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1068,8 +1068,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, if (!get_oid("HEAD", &curr_head)) { write_state_text(state, "abort-safety", oid_to_hex(&curr_head)); if (!state->rebasing) - update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0, - UPDATE_REFS_DIE_ON_ERR); + update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0, + UPDATE_REFS_DIE_ON_ERR); } else { write_state_text(state, "abort-safety", ""); if (!state->rebasing) @@ -1134,11 +1134,11 @@ static const char *msgnum(const struct am_state *state) */ static void refresh_and_write_cache(void) { - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + struct lock_file lock_file = LOCK_INIT; - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write index file")); } @@ -1488,11 +1488,10 @@ static int run_apply(const struct am_state *state, const char *index_file) struct argv_array apply_opts = ARGV_ARRAY_INIT; struct apply_state apply_state; int res, opts_left; - static struct lock_file lock_file; int force_apply = 0; int options = 0; - if (init_apply_state(&apply_state, NULL, &lock_file)) + if (init_apply_state(&apply_state, NULL)) die("BUG: init_apply_state() failed"); argv_array_push(&apply_opts, "apply"); @@ -1686,8 +1685,8 @@ static void do_commit(const struct am_state *state) strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg), state->msg); - update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0, - UPDATE_REFS_DIE_ON_ERR); + update_ref(sb.buf, "HEAD", &commit, old_oid, 0, + UPDATE_REFS_DIE_ON_ERR); if (state->rebasing) { FILE *fp = xfopen(am_path(state, "rewritten"), "a"); @@ -1946,15 +1945,14 @@ next: */ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) { - struct lock_file *lock_file; + struct lock_file lock_file = LOCK_INIT; struct unpack_trees_options opts; struct tree_desc t[2]; if (parse_tree(head) || parse_tree(remote)) return -1; - lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); @@ -1970,11 +1968,11 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) init_tree_desc(&t[1], remote->buffer, remote->size); if (unpack_trees(2, t, &opts)) { - rollback_lock_file(lock_file); + rollback_lock_file(&lock_file); return -1; } - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); return 0; @@ -1986,15 +1984,14 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) */ static int merge_tree(struct tree *tree) { - struct lock_file *lock_file; + struct lock_file lock_file = LOCK_INIT; struct unpack_trees_options opts; struct tree_desc t[1]; if (parse_tree(tree)) return -1; - lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; @@ -2005,11 +2002,11 @@ static int merge_tree(struct tree *tree) init_tree_desc(&t[0], tree->buffer, tree->size); if (unpack_trees(1, t, &opts)) { - rollback_lock_file(lock_file); + rollback_lock_file(&lock_file); return -1; } - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); return 0; @@ -2135,7 +2132,7 @@ static void am_abort(struct am_state *state) am_rerere_clear(); - curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL); + curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL); has_curr_head = curr_branch && !is_null_oid(&curr_head); if (!has_curr_head) hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN); @@ -2147,9 +2144,9 @@ static void am_abort(struct am_state *state) clean_index(&curr_head, &orig_head); if (has_orig_head) - update_ref_oid("am --abort", "HEAD", &orig_head, - has_curr_head ? &curr_head : NULL, 0, - UPDATE_REFS_DIE_ON_ERR); + update_ref("am --abort", "HEAD", &orig_head, + has_curr_head ? &curr_head : NULL, 0, + UPDATE_REFS_DIE_ON_ERR); else if (curr_branch) delete_ref(NULL, curr_branch, NULL, REF_NODEREF); diff --git a/builtin/apply.c b/builtin/apply.c index 81b9a61c37..48d3989331 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -9,8 +9,6 @@ static const char * const apply_usage[] = { NULL }; -static struct lock_file lock_file; - int cmd_apply(int argc, const char **argv, const char *prefix) { int force_apply = 0; @@ -18,7 +16,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix) int ret; struct apply_state state; - if (init_apply_state(&state, prefix, &lock_file)) + if (init_apply_state(&state, prefix)) exit(128); argc = apply_parse_options(argc, argv, diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index 3324229025..35d2105f94 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -2,19 +2,128 @@ #include "cache.h" #include "parse-options.h" #include "bisect.h" +#include "refs.h" + +static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS") +static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV") +static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK") static const char * const git_bisect_helper_usage[] = { N_("git bisect--helper --next-all [--no-checkout]"), + N_("git bisect--helper --write-terms <bad_term> <good_term>"), + N_("git bisect--helper --bisect-clean-state"), NULL }; +/* + * Check whether the string `term` belongs to the set of strings + * included in the variable arguments. + */ +LAST_ARG_MUST_BE_NULL +static int one_of(const char *term, ...) +{ + int res = 0; + va_list matches; + const char *match; + + va_start(matches, term); + while (!res && (match = va_arg(matches, const char *))) + res = !strcmp(term, match); + va_end(matches); + + return res; +} + +static int check_term_format(const char *term, const char *orig_term) +{ + int res; + char *new_term = xstrfmt("refs/bisect/%s", term); + + res = check_refname_format(new_term, 0); + free(new_term); + + if (res) + return error(_("'%s' is not a valid term"), term); + + if (one_of(term, "help", "start", "skip", "next", "reset", + "visualize", "replay", "log", "run", "terms", NULL)) + return error(_("can't use the builtin command '%s' as a term"), term); + + /* + * In theory, nothing prevents swapping completely good and bad, + * but this situation could be confusing and hasn't been tested + * enough. Forbid it for now. + */ + + if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) || + (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL))) + return error(_("can't change the meaning of the term '%s'"), term); + + return 0; +} + +static int write_terms(const char *bad, const char *good) +{ + FILE *fp = NULL; + int res; + + if (!strcmp(bad, good)) + return error(_("please use two different terms")); + + if (check_term_format(bad, "bad") || check_term_format(good, "good")) + return -1; + + fp = fopen(git_path_bisect_terms(), "w"); + if (!fp) + return error_errno(_("could not open the file BISECT_TERMS")); + + res = fprintf(fp, "%s\n%s\n", bad, good); + res |= fclose(fp); + return (res < 0) ? -1 : 0; +} + +static int is_expected_rev(const char *expected_hex) +{ + struct strbuf actual_hex = STRBUF_INIT; + int res = 0; + if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) { + strbuf_trim(&actual_hex); + res = !strcmp(actual_hex.buf, expected_hex); + } + strbuf_release(&actual_hex); + return res; +} + +static void check_expected_revs(const char **revs, int rev_nr) +{ + int i; + + for (i = 0; i < rev_nr; i++) { + if (!is_expected_rev(revs[i])) { + unlink_or_warn(git_path_bisect_ancestors_ok()); + unlink_or_warn(git_path_bisect_expected_rev()); + } + } +} + int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { - int next_all = 0; + enum { + NEXT_ALL = 1, + WRITE_TERMS, + BISECT_CLEAN_STATE, + CHECK_EXPECTED_REVS + } cmdmode = 0; int no_checkout = 0; struct option options[] = { - OPT_BOOL(0, "next-all", &next_all, - N_("perform 'git bisect next'")), + OPT_CMDMODE(0, "next-all", &cmdmode, + N_("perform 'git bisect next'"), NEXT_ALL), + OPT_CMDMODE(0, "write-terms", &cmdmode, + N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS), + OPT_CMDMODE(0, "bisect-clean-state", &cmdmode, + N_("cleanup the bisection state"), BISECT_CLEAN_STATE), + OPT_CMDMODE(0, "check-expected-revs", &cmdmode, + N_("check for expected revs"), CHECK_EXPECTED_REVS), OPT_BOOL(0, "no-checkout", &no_checkout, N_("update BISECT_HEAD instead of checking out the current commit")), OPT_END() @@ -23,9 +132,25 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_bisect_helper_usage, 0); - if (!next_all) + if (!cmdmode) usage_with_options(git_bisect_helper_usage, options); - /* next-all */ - return bisect_next_all(prefix, no_checkout); + switch (cmdmode) { + case NEXT_ALL: + return bisect_next_all(prefix, no_checkout); + case WRITE_TERMS: + if (argc != 2) + return error(_("--write-terms requires two arguments")); + return write_terms(argv[0], argv[1]); + case BISECT_CLEAN_STATE: + if (argc != 0) + return error(_("--bisect-clean-state requires no arguments")); + return bisect_clean_state(); + case CHECK_EXPECTED_REVS: + check_expected_revs(argv, argc); + return 0; + default: + return error("BUG: unknown subcommand '%d'", cmdmode); + } + return 0; } diff --git a/builtin/branch.c b/builtin/branch.c index 79dc9181fd..b1ed649300 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -125,7 +125,7 @@ static int branch_merged(int kind, const char *name, if (upstream && (reference_name = reference_name_to_free = resolve_refdup(upstream, RESOLVE_REF_READING, - oid.hash, NULL)) != NULL) + &oid, NULL)) != NULL) reference_rev = lookup_commit_reference(&oid); } if (!reference_rev) @@ -241,7 +241,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE | RESOLVE_REF_ALLOW_BAD_NAME, - oid.hash, &flags); + &oid, &flags); if (!target) { error(remote_branch ? _("remote-tracking branch '%s' not found.") @@ -257,7 +257,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, goto next; } - if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : oid.hash, + if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid, REF_NODEREF)) { error(remote_branch ? _("Error deleting remote-tracking branch '%s'") @@ -636,7 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) track = git_branch_track; - head = resolve_refdup("HEAD", 0, head_oid.hash, NULL); + head = resolve_refdup("HEAD", 0, &head_oid, NULL); if (!head) die(_("Failed to resolve HEAD as a valid ref.")); if (!strcmp(head, "HEAD")) diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c index 6c40ff110b..bc67d3f0a8 100644 --- a/builtin/check-ref-format.c +++ b/builtin/check-ref-format.c @@ -39,12 +39,14 @@ static char *collapse_slashes(const char *refname) static int check_ref_format_branch(const char *arg) { struct strbuf sb = STRBUF_INIT; + const char *name; int nongit; setup_git_directory_gently(&nongit); - if (strbuf_check_branch_ref(&sb, arg)) + if (strbuf_check_branch_ref(&sb, arg) || + !skip_prefix(sb.buf, "refs/heads/", &name)) die("'%s' is not a valid branch name", arg); - printf("%s\n", sb.buf + 11); + printf("%s\n", name); strbuf_release(&sb); return 0; } diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 39c8be05dc..b0e78b819d 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -129,8 +129,6 @@ static const char * const builtin_checkout_index_usage[] = { NULL }; -static struct lock_file lock_file; - static int option_parse_stage(const struct option *opt, const char *arg, int unset) { @@ -150,7 +148,7 @@ static int option_parse_stage(const struct option *opt, int cmd_checkout_index(int argc, const char **argv, const char *prefix) { int i; - int newfd = -1; + struct lock_file lock_file = LOCK_INIT; int all = 0; int read_from_stdin = 0; int prefix_length; @@ -206,7 +204,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (index_opt && !state.base_dir_len && !to_tempfile) { state.refresh_cache = 1; state.istate = &the_index; - newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); } /* Check out named files first */ @@ -251,7 +249,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (all) checkout_all(prefix, prefix_length); - if (0 <= newfd && + if (is_lock_file_locked(&lock_file) && write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die("Unable to write new index file"); return 0; diff --git a/builtin/checkout.c b/builtin/checkout.c index fc4f8fd2ea..6c2b4cd419 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -247,7 +247,7 @@ static int checkout_paths(const struct checkout_opts *opts, struct object_id rev; struct commit *head; int errs = 0; - struct lock_file *lock_file; + struct lock_file lock_file = LOCK_INIT; if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with updating paths"), "--track"); @@ -275,9 +275,7 @@ static int checkout_paths(const struct checkout_opts *opts, return run_add_interactive(revision, "--patch=checkout", &opts->pathspec); - lock_file = xcalloc(1, sizeof(struct lock_file)); - - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(&opts->pathspec) < 0) return error(_("index file corrupt")); @@ -376,10 +374,10 @@ static int checkout_paths(const struct checkout_opts *opts, } errs |= finish_delayed_checkout(&state); - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); - read_ref_full("HEAD", 0, rev.hash, NULL); + read_ref_full("HEAD", 0, &rev, NULL); head = lookup_commit_reference_gently(&rev, 1); errs |= post_checkout_hook(head, head, 0); @@ -472,9 +470,9 @@ static int merge_working_tree(const struct checkout_opts *opts, int *writeout_error) { int ret; - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + struct lock_file lock_file = LOCK_INIT; - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(NULL) < 0) return error(_("index file corrupt")); @@ -591,7 +589,7 @@ static int merge_working_tree(const struct checkout_opts *opts, if (!cache_tree_fully_valid(active_cache_tree)) cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); if (!opts->force && !opts->quiet) @@ -664,7 +662,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts, if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) { /* Nothing to do. */ } else if (opts->force_detach || !new->path) { /* No longer on any branch. */ - update_ref(msg.buf, "HEAD", new->commit->object.oid.hash, NULL, + update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); if (!opts->quiet) { if (old->path && @@ -827,7 +825,7 @@ static int switch_branches(const struct checkout_opts *opts, struct object_id rev; int flag, writeout_error = 0; memset(&old, 0, sizeof(old)); - old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag); + old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag); if (old.path) old.commit = lookup_commit_reference_gently(&rev, 1); if (!(flag & REF_ISSYMREF)) @@ -1038,7 +1036,7 @@ static int parse_branchname_arg(int argc, const char **argv, setup_branch_path(new); if (!check_refname_format(new->path, 0) && - !read_ref(new->path, branch_rev.hash)) + !read_ref(new->path, &branch_rev)) oidcpy(rev, &branch_rev); else new->path = NULL; /* not an existing branch */ @@ -1136,7 +1134,7 @@ static int checkout_branch(struct checkout_opts *opts, struct object_id rev; int flag; - if (!read_ref_full("HEAD", 0, rev.hash, &flag) && + if (!read_ref_full("HEAD", 0, &rev, &flag) && (flag & REF_ISSYMREF) && is_null_oid(&rev)) return switch_unborn_to_new_branch(opts); } diff --git a/builtin/clone.c b/builtin/clone.c index dbddd98f80..cf6eddc9c5 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -588,7 +588,7 @@ static void write_remote_refs(const struct ref *local_refs) for (r = local_refs; r; r = r->next) { if (!r->peer_ref) continue; - if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash, + if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid, 0, NULL, &err)) die("%s", err.buf); } @@ -610,12 +610,12 @@ static void write_followtags(const struct ref *refs, const char *msg) continue; if (!has_object_file(&ref->old_oid)) continue; - update_ref(msg, ref->name, ref->old_oid.hash, - NULL, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref(msg, ref->name, &ref->old_oid, NULL, 0, + UPDATE_REFS_DIE_ON_ERR); } } -static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) +static int iterate_ref_map(void *cb_data, struct object_id *oid) { struct ref **rm = cb_data; struct ref *ref = *rm; @@ -630,7 +630,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) if (!ref) return -1; - hashcpy(sha1, ref->old_oid.hash); + oidcpy(oid, &ref->old_oid); *rm = ref->next; return 0; } @@ -682,23 +682,23 @@ static void update_head(const struct ref *our, const struct ref *remote, if (create_symref("HEAD", our->name, NULL) < 0) die(_("unable to update HEAD")); if (!option_bare) { - update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0, + update_ref(msg, "HEAD", &our->old_oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR); install_branch_config(0, head, option_origin, our->name); } } else if (our) { struct commit *c = lookup_commit_reference(&our->old_oid); /* --branch specifies a non-branch (i.e. tags), detach HEAD */ - update_ref(msg, "HEAD", c->object.oid.hash, - NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); + update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NODEREF, + UPDATE_REFS_DIE_ON_ERR); } else if (remote) { /* * We know remote HEAD points to a non-branch, or * HEAD points to a branch but we don't know which one. * Detach HEAD in all these cases. */ - update_ref(msg, "HEAD", remote->old_oid.hash, - NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); + update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NODEREF, + UPDATE_REFS_DIE_ON_ERR); } } @@ -706,7 +706,7 @@ static int checkout(int submodule_progress) { struct object_id oid; char *head; - struct lock_file *lock_file; + struct lock_file lock_file = LOCK_INIT; struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; @@ -715,7 +715,7 @@ static int checkout(int submodule_progress) if (option_no_checkout) return 0; - head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL); + head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL); if (!head) { warning(_("remote HEAD refers to nonexistent ref, " "unable to checkout.\n")); @@ -733,8 +733,7 @@ static int checkout(int submodule_progress) /* We need to be in the new work tree for the checkout */ setup_work_tree(); - lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); memset(&opts, 0, sizeof opts); opts.update = 1; @@ -750,7 +749,7 @@ static int checkout(int submodule_progress) if (unpack_trees(1, &t, &opts) < 0) die(_("unable to checkout working tree")); - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1), diff --git a/builtin/commit.c b/builtin/commit.c index d75b3805ea..c38542ee46 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -355,7 +355,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix refresh_cache_or_die(refresh_flags); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); @@ -374,7 +374,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { if (reopen_lock_file(&index_lock) < 0) die(_("unable to write index file")); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to update temporary index")); } else warning(_("Failed to update main cache tree")); @@ -401,7 +401,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new_index file")); commit_style = COMMIT_NORMAL; ret = get_lock_file_path(&index_lock); @@ -474,7 +474,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix add_remove_files(&partial); refresh_cache(REFRESH_QUIET); update_main_cache_tree(WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new_index file")); hold_lock_file_for_update(&false_lock, @@ -486,7 +486,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &false_lock, 0)) die(_("unable to write temporary index file")); discard_cache(); @@ -1492,6 +1492,8 @@ static void print_summary(const char *prefix, const struct object_id *oid, diff_setup_done(&rev.diffopt); head = resolve_ref_unsafe("HEAD", 0, NULL, NULL); + if (!head) + die_errno(_("unable to resolve HEAD after creating commit")); if (!strcmp(head, "HEAD")) head = _("detached HEAD"); else @@ -1788,9 +1790,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, "HEAD", oid.hash, + ref_transaction_update(transaction, "HEAD", &oid, current_head - ? current_head->object.oid.hash : null_sha1, + ? ¤t_head->object.oid : &null_oid, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { rollback_index_files(); diff --git a/builtin/describe.c b/builtin/describe.c index 29075dbd0f..e14e162ef6 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -7,12 +7,12 @@ #include "builtin.h" #include "exec_cmd.h" #include "parse-options.h" +#include "revision.h" #include "diff.h" #include "hashmap.h" #include "argv-array.h" #include "run-command.h" -#define SEEN (1u << 0) #define MAX_TAGS (FLAG_BITS - 1) static const char * const describe_usage[] = { @@ -181,7 +181,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi } /* Is it annotated? */ - if (!peel_ref(path, peeled.hash)) { + if (!peel_ref(path, &peeled)) { is_annotated = !!oidcmp(oid, &peeled); } else { oidcpy(&peeled, oid); @@ -543,7 +543,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) } } else if (dirty) { static struct lock_file index_lock; - int fd; + struct rev_info revs; + struct argv_array args = ARGV_ARRAY_INIT; + int fd, result; read_cache_preload(NULL); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, @@ -552,8 +554,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (0 <= fd) update_index_if_able(&the_index, &index_lock); - if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, - diff_index_args, prefix)) + init_revisions(&revs, prefix); + argv_array_pushv(&args, diff_index_args); + if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1) + BUG("malformed internal diff-index command line"); + result = run_diff_index(&revs, 0); + + if (!diff_result_code(&revs.diffopt, result)) suffix = NULL; else suffix = dirty; diff --git a/builtin/diff.c b/builtin/diff.c index f5bbd4d757..aa6f746795 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -203,17 +203,16 @@ static int builtin_diff_combined(struct rev_info *revs, static void refresh_index_quietly(void) { - struct lock_file *lock_file; + struct lock_file lock_file = LOCK_INIT; int fd; - lock_file = xcalloc(1, sizeof(struct lock_file)); - fd = hold_locked_index(lock_file, 0); + fd = hold_locked_index(&lock_file, 0); if (fd < 0) return; discard_cache(); read_cache(); refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); - update_index_if_able(&the_index, lock_file); + update_index_if_able(&the_index, &lock_file); } static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv) diff --git a/builtin/difftool.c b/builtin/difftool.c index b2d3ba7539..bcc79d1888 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -616,7 +616,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 || write_locked_index(&wtindex, &lock, COMMIT_LOCK)) { ret = error("could not write %s", buf.buf); - rollback_lock_file(&lock); goto finish; } changed_files(&wt_modified, buf.buf, workdir); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 2fb60d6d48..d74c73f777 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -823,7 +823,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) if (e->flags & UNINTERESTING) continue; - if (dwim_ref(e->name, strlen(e->name), oid.hash, &full_name) != 1) + if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1) continue; if (refspecs) { diff --git a/builtin/fetch.c b/builtin/fetch.c index 225c734924..e705237fa9 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -457,8 +457,8 @@ static int s_update_ref(const char *action, transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref->name, - ref->new_oid.hash, - check_old ? ref->old_oid.hash : NULL, + &ref->new_oid, + check_old ? &ref->old_oid : NULL, 0, msg, &err)) goto fail; @@ -727,7 +727,7 @@ static int update_local_ref(struct ref *ref, } } -static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) +static int iterate_ref_map(void *cb_data, struct object_id *oid) { struct ref **rm = cb_data; struct ref *ref = *rm; @@ -737,7 +737,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) if (!ref) return -1; /* end of the list */ *rm = ref->next; - hashcpy(sha1, ref->old_oid.hash); + oidcpy(oid, &ref->old_oid); return 0; } diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index e99b5ddbf9..b69f7d3be2 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -603,7 +603,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out, /* get current branch */ current_branch = current_branch_to_free = - resolve_refdup("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL); + resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL); if (!current_branch) die("No current branch"); if (starts_with(current_branch, "refs/heads/")) diff --git a/builtin/fsck.c b/builtin/fsck.c index 56afe405b8..5f91116d73 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -555,7 +555,7 @@ static int fsck_head_link(void) if (verbose) fprintf(stderr, "Checking HEAD link\n"); - head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, NULL); + head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL); if (!head_points_at) { errors_found |= ERROR_REFS; return error("Invalid HEAD"); diff --git a/builtin/grep.c b/builtin/grep.c index 2d65f27d01..5a6cfe6b45 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -431,7 +431,9 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject, * store is no longer global and instead is a member of the repository * object. */ + grep_read_lock(); add_to_alternates_memory(submodule.objectdir); + grep_read_unlock(); if (oid) { struct object *object; diff --git a/builtin/log.c b/builtin/log.c index d81a09051e..ba9d4cd786 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -975,7 +975,7 @@ static char *find_branch_name(struct rev_info *rev) return NULL; ref = rev->cmdline.rev[positive].name; tip_oid = &rev->cmdline.rev[positive].item->oid; - if (dwim_ref(ref, strlen(ref), branch_oid.hash, &full_ref) && + if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) && skip_prefix(full_ref, "refs/heads/", &v) && !oidcmp(tip_oid, &branch_oid)) branch = xstrdup(v); diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 6dbd167d3b..e99f5405ce 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -156,7 +156,7 @@ static int handle_fork_point(int argc, const char **argv) struct commit_list *bases; int i, ret = 0; - switch (dwim_ref(argv[0], strlen(argv[0]), oid.hash, &refname)) { + switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) { case 0: die("No such ref: '%s'", argv[0]); case 1: diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c index 684411694f..beb0623d56 100644 --- a/builtin/merge-ours.c +++ b/builtin/merge-ours.c @@ -9,26 +9,24 @@ */ #include "git-compat-util.h" #include "builtin.h" +#include "diff.h" static const char builtin_merge_ours_usage[] = "git merge-ours <base>... -- HEAD <remote>..."; -static const char *diff_index_args[] = { - "diff-index", "--quiet", "--cached", "HEAD", "--", NULL -}; -#define NARGS (ARRAY_SIZE(diff_index_args) - 1) - int cmd_merge_ours(int argc, const char **argv, const char *prefix) { if (argc == 2 && !strcmp(argv[1], "-h")) usage(builtin_merge_ours_usage); /* - * We need to exit with 2 if the index does not match our HEAD tree, - * because the current index is what we will be committing as the - * merge result. + * The contents of the current index becomes the tree we + * commit. The index must match HEAD, or this merge cannot go + * through. */ - if (cmd_diff_index(NARGS, diff_index_args, prefix)) + if (read_cache() < 0) + die_errno("read_cache failed"); + if (index_differs_from("HEAD", 0, 0)) exit(2); exit(0); } diff --git a/builtin/merge.c b/builtin/merge.c index ab5ffe85e8..6071dbfe34 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -405,9 +405,8 @@ static void finish(struct commit *head_commit, printf(_("No merge message -- not updating HEAD\n")); else { const char *argv_gc_auto[] = { "gc", "--auto", NULL }; - update_ref(reflog_message.buf, "HEAD", - new_head->hash, head->hash, 0, - UPDATE_REFS_DIE_ON_ERR); + update_ref(reflog_message.buf, "HEAD", new_head, head, + 0, UPDATE_REFS_DIE_ON_ERR); /* * We ignore errors in 'gc --auto', since the * user should see them. @@ -455,7 +454,7 @@ static void merge_name(const char *remote, struct strbuf *msg) if (!remote_head) die(_("'%s' does not point to a commit"), remote); - if (dwim_ref(remote, strlen(remote), branch_head.hash, &found_ref) > 0) { + if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) { if (starts_with(found_ref, "refs/heads/")) { strbuf_addf(msg, "%s\t\tbranch '%s' of .\n", oid_to_hex(&branch_head), remote); @@ -1143,7 +1142,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * Check if we are _not_ on a detached HEAD, i.e. if there is a * current branch. */ - branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL); + branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL); if (branch) skip_prefix(branch, "refs/heads/", &branch); if (!branch || is_null_oid(&head_oid)) @@ -1261,8 +1260,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) die(_("Can merge only exactly one commit into empty head")); remote_head_oid = &remoteheads->item->object.oid; read_empty(remote_head_oid->hash, 0); - update_ref("initial pull", "HEAD", remote_head_oid->hash, - NULL, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0, + UPDATE_REFS_DIE_ON_ERR); goto done; } @@ -1357,8 +1356,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) free(list); } - update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash, - NULL, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref("updating ORIG_HEAD", "ORIG_HEAD", + &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR); if (remoteheads && !common) { /* No common ancestors found. */ diff --git a/builtin/notes.c b/builtin/notes.c index 8e54f2d146..12afdf1907 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -724,7 +724,7 @@ static int merge_commit(struct notes_merge_options *o) init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); o->local_ref = local_ref_to_free = - resolve_refdup("NOTES_MERGE_REF", 0, oid.hash, NULL); + resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL); if (!o->local_ref) die(_("failed to resolve NOTES_MERGE_REF")); @@ -736,8 +736,8 @@ static int merge_commit(struct notes_merge_options *o) format_commit_message(partial, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); strbuf_insert(&msg, 0, "notes: ", 7); - update_ref(msg.buf, o->local_ref, oid.hash, - is_null_oid(&parent_oid) ? NULL : parent_oid.hash, + update_ref(msg.buf, o->local_ref, &oid, + is_null_oid(&parent_oid) ? NULL : &parent_oid, 0, UPDATE_REFS_DIE_ON_ERR); free_notes(t); @@ -850,12 +850,12 @@ static int merge(int argc, const char **argv, const char *prefix) if (result >= 0) /* Merge resulted (trivially) in result_oid */ /* Update default notes ref with new commit */ - update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL, - 0, UPDATE_REFS_DIE_ON_ERR); + update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0, + UPDATE_REFS_DIE_ON_ERR); else { /* Merge has unresolved conflicts */ const struct worktree *wt; /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */ - update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL, + update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR); /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */ wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref()); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 6e77dfd444..631de28761 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -151,7 +151,7 @@ static unsigned long do_compress(void **pptr, unsigned long size) } static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f, - const unsigned char *sha1) + const struct object_id *oid) { git_zstream stream; unsigned char ibuf[1024 * 16]; @@ -165,7 +165,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi int zret = Z_OK; readlen = read_istream(st, ibuf, sizeof(ibuf)); if (readlen == -1) - die(_("unable to read %s"), sha1_to_hex(sha1)); + die(_("unable to read %s"), oid_to_hex(oid)); stream.next_in = ibuf; stream.avail_in = readlen; @@ -339,7 +339,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent sha1write(f, header, hdrlen); } if (st) { - datalen = write_large_blob_data(st, f, entry->idx.oid.hash); + datalen = write_large_blob_data(st, f, &entry->idx.oid); close_istream(st); } else { sha1write(f, buf, datalen); @@ -557,13 +557,13 @@ static enum write_one_status write_one(struct sha1file *f, static int mark_tagged(const char *path, const struct object_id *oid, int flag, void *cb_data) { - unsigned char peeled[20]; + struct object_id peeled; struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL); if (entry) entry->tagged = 1; - if (!peel_ref(path, peeled)) { - entry = packlist_find(&to_pack, peeled, NULL); + if (!peel_ref(path, &peeled)) { + entry = packlist_find(&to_pack, peeled.hash, NULL); if (entry) entry->tagged = 1; } @@ -792,7 +792,7 @@ static void write_pack_file(void) write_order = compute_write_order(); do { - unsigned char sha1[20]; + struct object_id oid; char *pack_tmp_name = NULL; if (pack_to_stdout) @@ -823,13 +823,13 @@ static void write_pack_file(void) * If so, rewrite it like in fast-import */ if (pack_to_stdout) { - sha1close(f, sha1, CSUM_CLOSE); + sha1close(f, oid.hash, CSUM_CLOSE); } else if (nr_written == nr_remaining) { - sha1close(f, sha1, CSUM_FSYNC); + sha1close(f, oid.hash, CSUM_FSYNC); } else { - int fd = sha1close(f, sha1, 0); - fixup_pack_header_footer(fd, sha1, pack_tmp_name, - nr_written, sha1, offset); + int fd = sha1close(f, oid.hash, 0); + fixup_pack_header_footer(fd, oid.hash, pack_tmp_name, + nr_written, oid.hash, offset); close(fd); if (write_bitmap_index) { warning(_(no_split_warning)); @@ -863,16 +863,16 @@ static void write_pack_file(void) strbuf_addf(&tmpname, "%s-", base_name); if (write_bitmap_index) { - bitmap_writer_set_checksum(sha1); + bitmap_writer_set_checksum(oid.hash); bitmap_writer_build_type_index(written_list, nr_written); } finish_tmp_packfile(&tmpname, pack_tmp_name, written_list, nr_written, - &pack_idx_opts, sha1); + &pack_idx_opts, oid.hash); if (write_bitmap_index) { - strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1)); + strbuf_addf(&tmpname, "%s.bitmap", oid_to_hex(&oid)); stop_progress(&progress_state); @@ -887,7 +887,7 @@ static void write_pack_file(void) strbuf_release(&tmpname); free(pack_tmp_name); - puts(sha1_to_hex(sha1)); + puts(oid_to_hex(&oid)); } /* mark written objects as written to previous pack */ @@ -928,13 +928,13 @@ static int no_try_delta(const char *path) * found the item, since that saves us from having to look it up again a * few lines later when we want to add the new entry. */ -static int have_duplicate_entry(const unsigned char *sha1, +static int have_duplicate_entry(const struct object_id *oid, int exclude, uint32_t *index_pos) { struct object_entry *entry; - entry = packlist_find(&to_pack, sha1, index_pos); + entry = packlist_find(&to_pack, oid->hash, index_pos); if (!entry) return 0; @@ -990,7 +990,7 @@ static int want_found_object(int exclude, struct packed_git *p) * function finds if there is any pack that has the object and returns the pack * and its offset in these variables. */ -static int want_object_in_pack(const unsigned char *sha1, +static int want_object_in_pack(const struct object_id *oid, int exclude, struct packed_git **found_pack, off_t *found_offset) @@ -998,7 +998,7 @@ static int want_object_in_pack(const unsigned char *sha1, struct mru_entry *entry; int want; - if (!exclude && local && has_loose_object_nonlocal(sha1)) + if (!exclude && local && has_loose_object_nonlocal(oid->hash)) return 0; /* @@ -1019,7 +1019,7 @@ static int want_object_in_pack(const unsigned char *sha1, if (p == *found_pack) offset = *found_offset; else - offset = find_pack_entry_one(sha1, p); + offset = find_pack_entry_one(oid->hash, p); if (offset) { if (!*found_pack) { @@ -1039,7 +1039,7 @@ static int want_object_in_pack(const unsigned char *sha1, return 1; } -static void create_object_entry(const unsigned char *sha1, +static void create_object_entry(const struct object_id *oid, enum object_type type, uint32_t hash, int exclude, @@ -1050,7 +1050,7 @@ static void create_object_entry(const unsigned char *sha1, { struct object_entry *entry; - entry = packlist_alloc(&to_pack, sha1, index_pos); + entry = packlist_alloc(&to_pack, oid->hash, index_pos); entry->hash = hash; if (type) entry->type = type; @@ -1070,17 +1070,17 @@ static const char no_closure_warning[] = N_( "disabling bitmap writing, as some objects are not being packed" ); -static int add_object_entry(const unsigned char *sha1, enum object_type type, +static int add_object_entry(const struct object_id *oid, enum object_type type, const char *name, int exclude) { struct packed_git *found_pack = NULL; off_t found_offset = 0; uint32_t index_pos; - if (have_duplicate_entry(sha1, exclude, &index_pos)) + if (have_duplicate_entry(oid, exclude, &index_pos)) return 0; - if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset)) { + if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) { /* The pack is missing an object, so it will not have closure */ if (write_bitmap_index) { warning(_(no_closure_warning)); @@ -1089,7 +1089,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type, return 0; } - create_object_entry(sha1, type, pack_name_hash(name), + create_object_entry(oid, type, pack_name_hash(name), exclude, name && no_try_delta(name), index_pos, found_pack, found_offset); @@ -1097,27 +1097,27 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type, return 1; } -static int add_object_entry_from_bitmap(const unsigned char *sha1, +static int add_object_entry_from_bitmap(const struct object_id *oid, enum object_type type, int flags, uint32_t name_hash, struct packed_git *pack, off_t offset) { uint32_t index_pos; - if (have_duplicate_entry(sha1, 0, &index_pos)) + if (have_duplicate_entry(oid, 0, &index_pos)) return 0; - if (!want_object_in_pack(sha1, 0, &pack, &offset)) + if (!want_object_in_pack(oid, 0, &pack, &offset)) return 0; - create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset); + create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset); display_progress(progress_state, nr_result); return 1; } struct pbase_tree_cache { - unsigned char sha1[20]; + struct object_id oid; int ref; int temporary; void *tree_data; @@ -1125,9 +1125,9 @@ struct pbase_tree_cache { }; static struct pbase_tree_cache *(pbase_tree_cache[256]); -static int pbase_tree_cache_ix(const unsigned char *sha1) +static int pbase_tree_cache_ix(const struct object_id *oid) { - return sha1[0] % ARRAY_SIZE(pbase_tree_cache); + return oid->hash[0] % ARRAY_SIZE(pbase_tree_cache); } static int pbase_tree_cache_ix_incr(int ix) { @@ -1144,14 +1144,14 @@ static struct pbase_tree { struct pbase_tree_cache pcache; } *pbase_tree; -static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1) +static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid) { struct pbase_tree_cache *ent, *nent; void *data; unsigned long size; enum object_type type; int neigh; - int my_ix = pbase_tree_cache_ix(sha1); + int my_ix = pbase_tree_cache_ix(oid); int available_ix = -1; /* pbase-tree-cache acts as a limited hashtable. @@ -1160,7 +1160,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1) */ for (neigh = 0; neigh < 8; neigh++) { ent = pbase_tree_cache[my_ix]; - if (ent && !hashcmp(ent->sha1, sha1)) { + if (ent && !oidcmp(&ent->oid, oid)) { ent->ref++; return ent; } @@ -1176,7 +1176,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1) /* Did not find one. Either we got a bogus request or * we need to read and perhaps cache. */ - data = read_sha1_file(sha1, &type, &size); + data = read_sha1_file(oid->hash, &type, &size); if (!data) return NULL; if (type != OBJ_TREE) { @@ -1202,7 +1202,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1) free(ent->tree_data); nent = ent; } - hashcpy(nent->sha1, sha1); + oidcpy(&nent->oid, oid); nent->tree_data = data; nent->tree_size = size; nent->ref = 1; @@ -1247,7 +1247,7 @@ static void add_pbase_object(struct tree_desc *tree, if (cmp < 0) return; if (name[cmplen] != '/') { - add_object_entry(entry.oid->hash, + add_object_entry(entry.oid, object_type(entry.mode), fullname, 1); return; @@ -1258,7 +1258,7 @@ static void add_pbase_object(struct tree_desc *tree, const char *down = name+cmplen+1; int downlen = name_cmp_len(down); - tree = pbase_tree_get(entry.oid->hash); + tree = pbase_tree_get(entry.oid); if (!tree) return; init_tree_desc(&sub, tree->tree_data, tree->tree_size); @@ -1317,7 +1317,7 @@ static void add_preferred_base_object(const char *name) cmplen = name_cmp_len(name); for (it = pbase_tree; it; it = it->next) { if (cmplen == 0) { - add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1); + add_object_entry(&it->pcache.oid, OBJ_TREE, NULL, 1); } else { struct tree_desc tree; @@ -1327,22 +1327,22 @@ static void add_preferred_base_object(const char *name) } } -static void add_preferred_base(unsigned char *sha1) +static void add_preferred_base(struct object_id *oid) { struct pbase_tree *it; void *data; unsigned long size; - unsigned char tree_sha1[20]; + struct object_id tree_oid; if (window <= num_preferred_base++) return; - data = read_object_with_reference(sha1, tree_type, &size, tree_sha1); + data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash); if (!data) return; for (it = pbase_tree; it; it = it->next) { - if (!hashcmp(it->pcache.sha1, tree_sha1)) { + if (!oidcmp(&it->pcache.oid, &tree_oid)) { free(data); return; } @@ -1352,7 +1352,7 @@ static void add_preferred_base(unsigned char *sha1) it->next = pbase_tree; pbase_tree = it; - hashcpy(it->pcache.sha1, tree_sha1); + oidcpy(&it->pcache.oid, &tree_oid); it->pcache.tree_data = data; it->pcache.tree_size = size; } @@ -2357,7 +2357,7 @@ static void add_tag_chain(const struct object_id *oid) die("unable to pack objects reachable from tag %s", oid_to_hex(oid)); - add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0); + add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0); if (tag->tagged->type != OBJ_TAG) return; @@ -2371,7 +2371,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag, struct object_id peeled; if (starts_with(path, "refs/tags/") && /* is a tag? */ - !peel_ref(path, peeled.hash) && /* peelable? */ + !peel_ref(path, &peeled) && /* peelable? */ packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */ add_tag_chain(oid); return 0; @@ -2505,8 +2505,9 @@ static int git_pack_config(const char *k, const char *v, void *cb) static void read_object_list_from_stdin(void) { - char line[40 + 1 + PATH_MAX + 2]; - unsigned char sha1[20]; + char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2]; + struct object_id oid; + const char *p; for (;;) { if (!fgets(line, sizeof(line), stdin)) { @@ -2520,17 +2521,17 @@ static void read_object_list_from_stdin(void) continue; } if (line[0] == '-') { - if (get_sha1_hex(line+1, sha1)) - die("expected edge sha1, got garbage:\n %s", + if (get_oid_hex(line+1, &oid)) + die("expected edge object ID, got garbage:\n %s", line); - add_preferred_base(sha1); + add_preferred_base(&oid); continue; } - if (get_sha1_hex(line, sha1)) - die("expected sha1, got garbage:\n %s", line); + if (parse_oid_hex(line, &oid, &p)) + die("expected object ID, got garbage:\n %s", line); - add_preferred_base_object(line+41); - add_object_entry(sha1, 0, line+41, 0); + add_preferred_base_object(p + 1); + add_object_entry(&oid, 0, p + 1, 0); } } @@ -2538,7 +2539,7 @@ static void read_object_list_from_stdin(void) static void show_commit(struct commit *commit, void *data) { - add_object_entry(commit->object.oid.hash, OBJ_COMMIT, NULL, 0); + add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0); commit->object.flags |= OBJECT_ADDED; if (write_bitmap_index) @@ -2548,13 +2549,13 @@ static void show_commit(struct commit *commit, void *data) static void show_object(struct object *obj, const char *name, void *data) { add_preferred_base_object(name); - add_object_entry(obj->oid.hash, obj->type, name, 0); + add_object_entry(&obj->oid, obj->type, name, 0); obj->flags |= OBJECT_ADDED; } static void show_edge(struct commit *commit) { - add_preferred_base(commit->object.oid.hash); + add_preferred_base(&commit->object.oid); } struct in_pack_object { @@ -2601,7 +2602,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) memset(&in_pack, 0, sizeof(in_pack)); for (p = packed_git; p; p = p->next) { - const unsigned char *sha1; + struct object_id oid; struct object *o; if (!p->pack_local || p->pack_keep) @@ -2614,8 +2615,8 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) in_pack.alloc); for (i = 0; i < p->num_objects; i++) { - sha1 = nth_packed_object_sha1(p, i); - o = lookup_unknown_object(sha1); + nth_packed_object_oid(&oid, p, i); + o = lookup_unknown_object(oid.hash); if (!(o->flags & OBJECT_ADDED)) mark_in_pack_object(o, p, &in_pack); o->flags |= OBJECT_ADDED; @@ -2626,7 +2627,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) QSORT(in_pack.array, in_pack.nr, ofscmp); for (i = 0; i < in_pack.nr; i++) { struct object *o = in_pack.array[i].object; - add_object_entry(o->oid.hash, o->type, "", 0); + add_object_entry(&o->oid, o->type, "", 0); } } free(in_pack.array); @@ -2642,7 +2643,7 @@ static int add_loose_object(const struct object_id *oid, const char *path, return 0; } - add_object_entry(oid->hash, type, "", 0); + add_object_entry(oid, type, "", 0); return 0; } @@ -2658,7 +2659,7 @@ static void add_unreachable_loose_objects(void) NULL, NULL, NULL); } -static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) +static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) { static struct packed_git *last_found = (void *)1; struct packed_git *p; @@ -2667,7 +2668,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) while (p) { if ((!p->pack_local || p->pack_keep) && - find_pack_entry_one(sha1, p)) { + find_pack_entry_one(oid->hash, p)) { last_found = p; return 1; } @@ -2718,7 +2719,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs) for (i = 0; i < p->num_objects; i++) { nth_packed_object_oid(&oid, p, i); if (!packlist_find(&to_pack, oid.hash, NULL) && - !has_sha1_pack_kept_or_nonlocal(oid.hash) && + !has_sha1_pack_kept_or_nonlocal(&oid) && !loosened_object_can_be_discarded(&oid, p->mtime)) if (force_object_loose(oid.hash, p->mtime)) die("unable to force loose object"); diff --git a/builtin/pull.c b/builtin/pull.c index 6f772e8a22..a28f0ffadd 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -86,6 +86,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static enum rebase_type opt_rebase = -1; static char *opt_diffstat; static char *opt_log; +static char *opt_signoff; static char *opt_squash; static char *opt_commit; static char *opt_edit; @@ -142,6 +143,9 @@ static struct option pull_options[] = { OPT_PASSTHRU(0, "log", &opt_log, N_("n"), N_("add (at most <n>) entries from shortlog to merge commit message"), PARSE_OPT_OPTARG), + OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL, + N_("add Signed-off-by:"), + PARSE_OPT_OPTARG), OPT_PASSTHRU(0, "squash", &opt_squash, NULL, N_("create a single commit instead of doing a merge"), PARSE_OPT_NOARG), @@ -544,7 +548,7 @@ static int pull_into_void(const struct object_id *merge_head, if (checkout_fast_forward(&empty_tree_oid, merge_head, 0)) return 1; - if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR)) + if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR)) return 1; return 0; @@ -594,6 +598,8 @@ static int run_merge(void) argv_array_push(&args, opt_diffstat); if (opt_log) argv_array_push(&args, opt_log); + if (opt_signoff) + argv_array_push(&args, opt_signoff); if (opt_squash) argv_array_push(&args, opt_squash); if (opt_commit) diff --git a/builtin/push.c b/builtin/push.c index 2ac8104229..1c28427d82 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -32,6 +32,8 @@ static const char **refspec; static int refspec_nr; static int refspec_alloc; +static struct string_list push_options_config = STRING_LIST_INIT_DUP; + static void add_refspec(const char *ref) { refspec_nr++; @@ -503,6 +505,15 @@ static int git_push_config(const char *k, const char *v, void *cb) int val = git_config_bool(k, v) ? RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; recurse_submodules = val; + } else if (!strcmp(k, "push.pushoption")) { + if (!v) + return config_error_nonbool(k); + else + if (!*v) + string_list_clear(&push_options_config, 0); + else + string_list_append(&push_options_config, v); + return 0; } return git_default_config(k, v, NULL); @@ -515,7 +526,8 @@ int cmd_push(int argc, const char **argv, const char *prefix) int push_cert = -1; int rc; const char *repo = NULL; /* default repository */ - struct string_list push_options = STRING_LIST_INIT_DUP; + struct string_list push_options_cmdline = STRING_LIST_INIT_DUP; + struct string_list *push_options; const struct string_list_item *item; struct option options[] = { @@ -551,7 +563,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC), - OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")), + OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")), OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), TRANSPORT_FAMILY_IPV4), OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), @@ -562,6 +574,9 @@ int cmd_push(int argc, const char **argv, const char *prefix) packet_trace_identity("push"); git_config(git_push_config, &flags); argc = parse_options(argc, argv, prefix, options, push_usage, 0); + push_options = (push_options_cmdline.nr + ? &push_options_cmdline + : &push_options_config); set_push_cert_flags(&flags, push_cert); if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR)))) @@ -584,12 +599,13 @@ int cmd_push(int argc, const char **argv, const char *prefix) set_refspecs(argv + 1, argc - 1, repo); } - for_each_string_list_item(item, &push_options) + for_each_string_list_item(item, push_options) if (strchr(item->string, '\n')) die(_("push options must not have new line characters")); - rc = do_push(repo, flags, &push_options); - string_list_clear(&push_options, 0); + rc = do_push(repo, flags, push_options); + string_list_clear(&push_options_cmdline, 0); + string_list_clear(&push_options_config, 0); if (rc == -1) usage_with_options(push_usage, options); else diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index cc48767405..4d37a160d7 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -870,7 +870,7 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", _(refuse_unconfigured_deny_delete_current_msg)); } -static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]); +static int command_singleton_iterator(void *cb_data, struct object_id *oid); static int update_shallow_ref(struct command *cmd, struct shallow_info *si) { static struct lock_file shallow_lock; @@ -1139,7 +1139,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) } if (ref_transaction_delete(transaction, namespaced_name, - old_oid ? old_oid->hash : NULL, + old_oid, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); @@ -1156,7 +1156,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (ref_transaction_update(transaction, namespaced_name, - new_oid->hash, old_oid->hash, + new_oid, old_oid, 0, "push", &err)) { rp_error("%s", err.buf); @@ -1270,7 +1270,7 @@ static void check_aliased_updates(struct command *commands) string_list_clear(&ref_list, 0); } -static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]) +static int command_singleton_iterator(void *cb_data, struct object_id *oid) { struct command **cmd_list = cb_data; struct command *cmd = *cmd_list; @@ -1278,7 +1278,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]) if (!cmd || is_null_oid(&cmd->new_oid)) return -1; /* end of list */ *cmd_list = NULL; /* this returns only one */ - hashcpy(sha1, cmd->new_oid.hash); + oidcpy(oid, &cmd->new_oid); return 0; } @@ -1309,7 +1309,7 @@ struct iterate_data { struct shallow_info *si; }; -static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20]) +static int iterate_receive_command_list(void *cb_data, struct object_id *oid) { struct iterate_data *data = cb_data; struct command **cmd_list = &data->cmds; @@ -1320,7 +1320,7 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20]) /* to be checked in update_shallow_ref() */ continue; if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) { - hashcpy(sha1, cmd->new_oid.hash); + oidcpy(oid, &cmd->new_oid); *cmd_list = cmd->next; return 0; } diff --git a/builtin/reflog.c b/builtin/reflog.c index 2067cca5b1..ab31a3b6aa 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -42,7 +42,7 @@ struct expire_reflog_policy_cb { }; struct collected_reflog { - unsigned char sha1[20]; + struct object_id oid; char reflog[FLEX_ARRAY]; }; @@ -385,7 +385,7 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus struct collect_reflog_cb *cb = cb_data; FLEX_ALLOC_STR(e, reflog, ref); - hashcpy(e->sha1, oid->hash); + oidcpy(&e->oid, oid); ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc); cb->e[cb->nr++] = e; return 0; @@ -589,7 +589,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) for (i = 0; i < collected.nr; i++) { struct collected_reflog *e = collected.e[i]; set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog); - status |= reflog_expire(e->reflog, e->sha1, flags, + status |= reflog_expire(e->reflog, &e->oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, @@ -601,13 +601,13 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) for (; i < argc; i++) { char *ref; - unsigned char sha1[20]; - if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) { + struct object_id oid; + if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) { status |= error("%s points nowhere!", argv[i]); continue; } set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref); - status |= reflog_expire(ref, sha1, flags, + status |= reflog_expire(ref, &oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, @@ -659,7 +659,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) for ( ; i < argc; i++) { const char *spec = strstr(argv[i], "@{"); - unsigned char sha1[20]; + struct object_id oid; char *ep, *ref; int recno; @@ -668,7 +668,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) continue; } - if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) { + if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) { status |= error("no reflog for '%s'", argv[i]); continue; } @@ -683,7 +683,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) cb.cmd.expire_total = 0; } - status |= reflog_expire(ref, sha1, flags, + status |= reflog_expire(ref, &oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, diff --git a/builtin/remote.c b/builtin/remote.c index 4f5cac96b0..a04ea50e40 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -565,7 +565,7 @@ static int read_remote_branches(const char *refname, item = string_list_append(rename->remote_branches, xstrdup(refname)); symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, &flag); - if (flag & REF_ISSYMREF) + if (symref && (flag & REF_ISSYMREF)) item->util = xstrdup(symref); else item->util = NULL; @@ -690,7 +690,7 @@ static int mv(int argc, const char **argv) int flag = 0; struct object_id oid; - read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag); + read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag); if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(NULL, item->string, NULL, REF_NODEREF)) diff --git a/builtin/replace.c b/builtin/replace.c index 3e71a77152..10078ae371 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -113,7 +113,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn) strbuf_addstr(&ref, oid_to_hex(&oid)); full_hex = ref.buf + base_len; - if (read_ref(ref.buf, oid.hash)) { + if (read_ref(ref.buf, &oid)) { error("replace ref '%s' not found.", full_hex); had_error = 1; continue; @@ -128,7 +128,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn) static int delete_replace_ref(const char *name, const char *ref, const struct object_id *oid) { - if (delete_ref(NULL, ref, oid->hash, 0)) + if (delete_ref(NULL, ref, oid, 0)) return 1; printf("Deleted replace ref '%s'\n", name); return 0; @@ -144,7 +144,7 @@ static void check_ref_valid(struct object_id *object, if (check_refname_format(ref->buf, 0)) die("'%s' is not a valid ref name.", ref->buf); - if (read_ref(ref->buf, prev->hash)) + if (read_ref(ref->buf, prev)) oidclr(prev); else if (!force) die("replace ref '%s' already exists", ref->buf); @@ -175,7 +175,7 @@ static int replace_object_oid(const char *object_ref, transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash, + ref_transaction_update(transaction, ref.buf, repl, &prev, 0, NULL, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); diff --git a/builtin/reset.c b/builtin/reset.c index 9cd89b2305..d4003f76ab 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -266,12 +266,12 @@ static int reset_refs(const char *rev, const struct object_id *oid) if (!get_oid("HEAD", &oid_orig)) { orig = &oid_orig; set_reflog_message(&msg, "updating ORIG_HEAD", NULL); - update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0, + update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0, UPDATE_REFS_MSG_ON_ERR); } else if (old_orig) - delete_ref(NULL, "ORIG_HEAD", old_orig->hash, 0); + delete_ref(NULL, "ORIG_HEAD", old_orig, 0); set_reflog_message(&msg, "updating HEAD", rev); - update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0, + update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0, UPDATE_REFS_MSG_ON_ERR); strbuf_release(&msg); return update_ref_status; diff --git a/builtin/rev-list.c b/builtin/rev-list.c index c1c74d4a79..9bf8d5991c 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -258,14 +258,14 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all) } static int show_object_fast( - const unsigned char *sha1, + const struct object_id *oid, enum object_type type, int exclude, uint32_t name_hash, struct packed_git *found_pack, off_t found_offset) { - fprintf(stdout, "%s\n", sha1_to_hex(sha1)); + fprintf(stdout, "%s\n", oid_to_hex(oid)); return 1; } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index a8d7e6f7ae..74aa644cbb 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -133,7 +133,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name) struct object_id discard; char *full; - switch (dwim_ref(name, strlen(name), discard.hash, &full)) { + switch (dwim_ref(name, strlen(name), &discard, &full)) { case 0: /* * Not found -- not a ref. We could diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 6fa1f62a88..2e24b5c330 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -705,8 +705,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) static const char *fake_av[2]; fake_av[0] = resolve_refdup("HEAD", - RESOLVE_REF_READING, - oid.hash, NULL); + RESOLVE_REF_READING, &oid, + NULL); fake_av[1] = NULL; av = fake_av; ac = 1; @@ -720,7 +720,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) die(Q_("only %d entry can be shown at one time.", "only %d entries can be shown at one time.", MAX_REVS), MAX_REVS); - if (!dwim_ref(*av, strlen(*av), oid.hash, &ref)) + if (!dwim_ref(*av, strlen(*av), &oid, &ref)) die(_("no such ref %s"), *av); /* Has the base been specified? */ @@ -731,7 +731,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) /* Ah, that is a date spec... */ timestamp_t at; at = approxidate(reflog_base); - read_ref_at(ref, flags, at, -1, oid.hash, NULL, + read_ref_at(ref, flags, at, -1, &oid, NULL, NULL, NULL, &base); } } @@ -743,7 +743,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) timestamp_t timestamp; int tz; - if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg, + if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg, ×tamp, &tz, NULL)) { reflog = i; break; @@ -775,7 +775,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } head = resolve_refdup("HEAD", RESOLVE_REF_READING, - head_oid.hash, NULL); + &head_oid, NULL); if (with_current_branch && head) { int has_head = 0; diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 013d241abc..41e5e71cad 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -38,7 +38,7 @@ static void show_one(const char *refname, const struct object_id *oid) if (!deref_tags) return; - if (!peel_ref(refname, peeled.hash)) { + if (!peel_ref(refname, &peeled)) { hex = find_unique_abbrev(peeled.hash, abbrev); printf("%s %s^{}\n", hex, refname); } @@ -197,7 +197,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix) struct object_id oid; if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) && - !read_ref(*pattern, oid.hash)) { + !read_ref(*pattern, &oid)) { show_one(*pattern, &oid); } else if (!quiet) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 06ed02f994..2086f0eb08 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -13,6 +13,16 @@ #include "remote.h" #include "refs.h" #include "connect.h" +#include "revision.h" +#include "diffcore.h" +#include "diff.h" + +#define OPT_QUIET (1 << 0) +#define OPT_CACHED (1 << 1) +#define OPT_RECURSIVE (1 << 2) + +typedef void (*each_submodule_fn)(const struct cache_entry *list_item, + void *cb_data); static char *get_default_remote(void) { @@ -219,6 +229,64 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr return 0; } +/* the result should be freed by the caller. */ +static char *get_submodule_displaypath(const char *path, const char *prefix) +{ + const char *super_prefix = get_super_prefix(); + + if (prefix && super_prefix) { + BUG("cannot have prefix '%s' and superprefix '%s'", + prefix, super_prefix); + } else if (prefix) { + struct strbuf sb = STRBUF_INIT; + char *displaypath = xstrdup(relative_path(path, prefix, &sb)); + strbuf_release(&sb); + return displaypath; + } else if (super_prefix) { + return xstrfmt("%s%s", super_prefix, path); + } else { + return xstrdup(path); + } +} + +static char *compute_rev_name(const char *sub_path, const char* object_id) +{ + struct strbuf sb = STRBUF_INIT; + const char ***d; + + static const char *describe_bare[] = { NULL }; + + static const char *describe_tags[] = { "--tags", NULL }; + + static const char *describe_contains[] = { "--contains", NULL }; + + static const char *describe_all_always[] = { "--all", "--always", NULL }; + + static const char **describe_argv[] = { describe_bare, describe_tags, + describe_contains, + describe_all_always, NULL }; + + for (d = describe_argv; *d; d++) { + struct child_process cp = CHILD_PROCESS_INIT; + prepare_submodule_repo_env(&cp.env_array); + cp.dir = sub_path; + cp.git_cmd = 1; + cp.no_stderr = 1; + + argv_array_push(&cp.args, "describe"); + argv_array_pushv(&cp.args, *d); + argv_array_push(&cp.args, object_id); + + if (!capture_command(&cp, &sb, 0)) { + strbuf_strip_suffix(&sb, "\n"); + return strbuf_detach(&sb, NULL); + } + } + + strbuf_release(&sb); + return NULL; +} + struct module_list { const struct cache_entry **entries; int alloc, nr; @@ -328,21 +396,29 @@ static int module_list(int argc, const char **argv, const char *prefix) return 0; } -static void init_submodule(const char *path, const char *prefix, int quiet) +static void for_each_listed_submodule(const struct module_list *list, + each_submodule_fn fn, void *cb_data) +{ + int i; + for (i = 0; i < list->nr; i++) + fn(list->entries[i], cb_data); +} + +struct init_cb { + const char *prefix; + unsigned int flags; +}; + +#define INIT_CB_INIT { NULL, 0 } + +static void init_submodule(const char *path, const char *prefix, + unsigned int flags) { const struct submodule *sub; struct strbuf sb = STRBUF_INIT; char *upd = NULL, *url = NULL, *displaypath; - if (prefix && get_super_prefix()) - die("BUG: cannot have prefix and superprefix"); - else if (prefix) - displaypath = xstrdup(relative_path(path, prefix, &sb)); - else if (get_super_prefix()) { - strbuf_addf(&sb, "%s%s", get_super_prefix(), path); - displaypath = strbuf_detach(&sb, NULL); - } else - displaypath = xstrdup(path); + displaypath = get_submodule_displaypath(path, prefix); sub = submodule_from_path(&null_oid, path); @@ -357,9 +433,9 @@ static void init_submodule(const char *path, const char *prefix, int quiet) * Set active flag for the submodule being initialized */ if (!is_submodule_active(the_repository, path)) { - strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.active", sub->name); git_config_set_gently(sb.buf, "true"); + strbuf_reset(&sb); } /* @@ -367,7 +443,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet) * To look up the url in .git/config, we must not fall back to * .gitmodules, so look it up directly. */ - strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.url", sub->name); if (git_config_get_string(sb.buf, &url)) { if (!sub->url) @@ -399,14 +474,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet) if (git_config_set_gently(sb.buf, url)) die(_("Failed to register url for submodule path '%s'"), displaypath); - if (!quiet) + if (!(flags & OPT_QUIET)) fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"), sub->name, url, displaypath); } + strbuf_reset(&sb); /* Copy "update" setting when it is not set yet */ - strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.update", sub->name); if (git_config_get_string(sb.buf, &upd) && sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) { @@ -426,12 +501,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet) free(upd); } +static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data) +{ + struct init_cb *info = cb_data; + init_submodule(list_item->name, info->prefix, info->flags); +} + static int module_init(int argc, const char **argv, const char *prefix) { + struct init_cb info = INIT_CB_INIT; struct pathspec pathspec; struct module_list list = MODULE_LIST_INIT; int quiet = 0; - int i; struct option module_init_options[] = { OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")), @@ -456,8 +537,165 @@ static int module_init(int argc, const char **argv, const char *prefix) if (!argc && git_config_get_value_multi("submodule.active")) module_list_active(&list); - for (i = 0; i < list.nr; i++) - init_submodule(list.entries[i]->name, prefix, quiet); + info.prefix = prefix; + if (quiet) + info.flags |= OPT_QUIET; + + for_each_listed_submodule(&list, init_submodule_cb, &info); + + return 0; +} + +struct status_cb { + const char *prefix; + unsigned int flags; +}; + +#define STATUS_CB_INIT { NULL, 0 } + +static void print_status(unsigned int flags, char state, const char *path, + const struct object_id *oid, const char *displaypath) +{ + if (flags & OPT_QUIET) + return; + + printf("%c%s %s", state, oid_to_hex(oid), displaypath); + + if (state == ' ' || state == '+') + printf(" (%s)", compute_rev_name(path, oid_to_hex(oid))); + + printf("\n"); +} + +static int handle_submodule_head_ref(const char *refname, + const struct object_id *oid, int flags, + void *cb_data) +{ + struct object_id *output = cb_data; + if (oid) + oidcpy(output, oid); + + return 0; +} + +static void status_submodule(const char *path, const struct object_id *ce_oid, + unsigned int ce_flags, const char *prefix, + unsigned int flags) +{ + char *displaypath; + struct argv_array diff_files_args = ARGV_ARRAY_INIT; + struct rev_info rev; + int diff_files_result; + + if (!submodule_from_path(&null_oid, path)) + die(_("no submodule mapping found in .gitmodules for path '%s'"), + path); + + displaypath = get_submodule_displaypath(path, prefix); + + if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) { + print_status(flags, 'U', path, &null_oid, displaypath); + goto cleanup; + } + + if (!is_submodule_active(the_repository, path)) { + print_status(flags, '-', path, ce_oid, displaypath); + goto cleanup; + } + + argv_array_pushl(&diff_files_args, "diff-files", + "--ignore-submodules=dirty", "--quiet", "--", + path, NULL); + + git_config(git_diff_basic_config, NULL); + init_revisions(&rev, prefix); + rev.abbrev = 0; + diff_files_args.argc = setup_revisions(diff_files_args.argc, + diff_files_args.argv, + &rev, NULL); + diff_files_result = run_diff_files(&rev, 0); + + if (!diff_result_code(&rev.diffopt, diff_files_result)) { + print_status(flags, ' ', path, ce_oid, + displaypath); + } else if (!(flags & OPT_CACHED)) { + struct object_id oid; + + if (refs_head_ref(get_submodule_ref_store(path), + handle_submodule_head_ref, &oid)) + die(_("could not resolve HEAD ref inside the" + "submodule '%s'"), path); + + print_status(flags, '+', path, &oid, displaypath); + } else { + print_status(flags, '+', path, ce_oid, displaypath); + } + + if (flags & OPT_RECURSIVE) { + struct child_process cpr = CHILD_PROCESS_INIT; + + cpr.git_cmd = 1; + cpr.dir = path; + prepare_submodule_repo_env(&cpr.env_array); + + argv_array_push(&cpr.args, "--super-prefix"); + argv_array_pushf(&cpr.args, "%s/", displaypath); + argv_array_pushl(&cpr.args, "submodule--helper", "status", + "--recursive", NULL); + + if (flags & OPT_CACHED) + argv_array_push(&cpr.args, "--cached"); + + if (flags & OPT_QUIET) + argv_array_push(&cpr.args, "--quiet"); + + if (run_command(&cpr)) + die(_("failed to recurse into submodule '%s'"), path); + } + +cleanup: + argv_array_clear(&diff_files_args); + free(displaypath); +} + +static void status_submodule_cb(const struct cache_entry *list_item, + void *cb_data) +{ + struct status_cb *info = cb_data; + status_submodule(list_item->name, &list_item->oid, list_item->ce_flags, + info->prefix, info->flags); +} + +static int module_status(int argc, const char **argv, const char *prefix) +{ + struct status_cb info = STATUS_CB_INIT; + struct pathspec pathspec; + struct module_list list = MODULE_LIST_INIT; + int quiet = 0; + + struct option module_status_options[] = { + OPT__QUIET(&quiet, N_("Suppress submodule status output")), + OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED), + OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE), + OPT_END() + }; + + const char *const git_submodule_helper_usage[] = { + N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"), + NULL + }; + + argc = parse_options(argc, argv, prefix, module_status_options, + git_submodule_helper_usage, 0); + + if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) + return 1; + + info.prefix = prefix; + if (quiet) + info.flags |= OPT_QUIET; + + for_each_listed_submodule(&list, status_submodule_cb, &info); return 0; } @@ -1144,7 +1382,7 @@ static int push_check(int argc, const char **argv, const char *prefix) argv++; argc--; /* Get the submodule's head ref and determine if it is detached */ - head = resolve_refdup("HEAD", 0, head_oid.hash, NULL); + head = resolve_refdup("HEAD", 0, &head_oid, NULL); if (!head) die(_("Failed to resolve HEAD as a valid ref.")); if (!strcmp(head, "HEAD")) @@ -1259,6 +1497,7 @@ static struct cmd_struct commands[] = { {"resolve-relative-url", resolve_relative_url, 0}, {"resolve-relative-url-test", resolve_relative_url_test, 0}, {"init", module_init, SUPPORT_SUPER_PREFIX}, + {"status", module_status, SUPPORT_SUPER_PREFIX}, {"remote-branch", resolve_remote_submodule_branch, 0}, {"push-check", push_check, 0}, {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, diff --git a/builtin/tag.c b/builtin/tag.c index b38329b593..a7e6a5b0f2 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -82,7 +82,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn, for (p = argv; *p; p++) { strbuf_reset(&ref); strbuf_addf(&ref, "refs/tags/%s", *p); - if (read_ref(ref.buf, oid.hash)) { + if (read_ref(ref.buf, &oid)) { error(_("tag '%s' not found."), *p); had_error = 1; continue; @@ -97,7 +97,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn, static int delete_tag(const char *name, const char *ref, const struct object_id *oid, const void *cb_data) { - if (delete_ref(NULL, ref, oid->hash, 0)) + if (delete_ref(NULL, ref, oid, 0)) return 1; printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); return 0; @@ -518,7 +518,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); - if (read_ref(ref.buf, prev.hash)) + if (read_ref(ref.buf, &prev)) oidclr(&prev); else if (!force) die(_("tag '%s' already exists"), tag); @@ -544,7 +544,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref.buf, object.hash, prev.hash, + ref_transaction_update(transaction, ref.buf, &object, &prev, create_reflog ? REF_FORCE_CREATE_REFLOG : 0, reflog_msg.buf, &err) || ref_transaction_commit(transaction, &err)) diff --git a/builtin/update-index.c b/builtin/update-index.c index bf7420b808..fefbe60167 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -328,7 +328,7 @@ static int process_directory(const char *path, int len, struct stat *st) if (S_ISGITLINK(ce->ce_mode)) { /* Do nothing to the index if there is no HEAD! */ - if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0) + if (resolve_gitlink_ref(path, "HEAD", &oid) < 0) return 0; return add_one_path(ce, path, len, st); @@ -354,7 +354,7 @@ static int process_directory(const char *path, int len, struct stat *st) } /* No match - should we add it as a gitlink? */ - if (!resolve_gitlink_ref(path, "HEAD", oid.hash)) + if (!resolve_gitlink_ref(path, "HEAD", &oid)) return add_one_path(NULL, path, len, st); /* Error out. */ @@ -679,9 +679,9 @@ static int unresolve_one(const char *path) static void read_head_pointers(void) { - if (read_ref("HEAD", head_oid.hash)) + if (read_ref("HEAD", &head_oid)) die("No HEAD -- no initial commit yet?"); - if (read_ref("MERGE_HEAD", merge_head_oid.hash)) { + if (read_ref("MERGE_HEAD", &merge_head_oid)) { fprintf(stderr, "Not in the middle of a merge.\n"); exit(0); } @@ -721,7 +721,7 @@ static int do_reupdate(int ac, const char **av, PATHSPEC_PREFER_CWD, prefix, av + 1); - if (read_ref("HEAD", head_oid.hash)) + if (read_ref("HEAD", &head_oid)) /* If there is no HEAD, that means it is an initial * commit. Update everything in the index. */ diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 6b90c5dead..cf1552b478 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -200,7 +200,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, die("update %s: extra input: %s", refname, next); if (ref_transaction_update(transaction, refname, - new_oid.hash, have_old ? old_oid.hash : NULL, + &new_oid, have_old ? &old_oid : NULL, update_flags | create_reflog_flag, msg, &err)) die("%s", err.buf); @@ -232,7 +232,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, if (*next != line_termination) die("create %s: extra input: %s", refname, next); - if (ref_transaction_create(transaction, refname, new_oid.hash, + if (ref_transaction_create(transaction, refname, &new_oid, update_flags | create_reflog_flag, msg, &err)) die("%s", err.buf); @@ -269,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, die("delete %s: extra input: %s", refname, next); if (ref_transaction_delete(transaction, refname, - have_old ? old_oid.hash : NULL, + have_old ? &old_oid : NULL, update_flags, msg, &err)) die("%s", err.buf); @@ -298,7 +298,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, if (*next != line_termination) die("verify %s: extra input: %s", refname, next); - if (ref_transaction_verify(transaction, refname, old_oid.hash, + if (ref_transaction_verify(transaction, refname, &old_oid, update_flags, &err)) die("%s", err.buf); @@ -434,10 +434,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) * NULL_SHA1 as "don't care" here: */ return delete_ref(msg, refname, - (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL, + (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL, flags); else - return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL, + return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL, flags | create_reflog_flag, UPDATE_REFS_DIE_ON_ERR); } diff --git a/builtin/worktree.c b/builtin/worktree.c index 7b9307aa58..ed043d5f1c 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -410,7 +410,7 @@ static void show_worktree_porcelain(struct worktree *wt) if (wt->is_bare) printf("bare\n"); else { - printf("HEAD %s\n", sha1_to_hex(wt->head_sha1)); + printf("HEAD %s\n", oid_to_hex(&wt->head_oid)); if (wt->is_detached) printf("detached\n"); else if (wt->head_ref) @@ -430,7 +430,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) strbuf_addstr(&sb, "(bare)"); else { strbuf_addf(&sb, "%-*s ", abbrev_len, - find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV)); + find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV)); if (wt->is_detached) strbuf_addstr(&sb, "(detached HEAD)"); else if (wt->head_ref) { @@ -455,7 +455,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen) if (path_len > *maxlen) *maxlen = path_len; - sha1_len = strlen(find_unique_abbrev(wt[i]->head_sha1, *abbrev)); + sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev)); if (sha1_len > *abbrev) *abbrev = sha1_len; } @@ -338,9 +338,9 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) if (e->item->flags & UNINTERESTING) continue; - if (dwim_ref(e->name, strlen(e->name), oid.hash, &ref) != 1) + if (dwim_ref(e->name, strlen(e->name), &oid, &ref) != 1) goto skip_write_ref; - if (read_ref_full(e->name, RESOLVE_REF_READING, oid.hash, &flag)) + if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag)) flag = 0; display_ref = (flag & REF_ISSYMREF) ? e->name : ref; diff --git a/cache-tree.c b/cache-tree.c index d3f7401278..e03e72c34a 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -602,11 +602,11 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix) { - int entries, was_valid, newfd; + int entries, was_valid; struct lock_file lock_file = LOCK_INIT; int ret = 0; - newfd = hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR); + hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR); entries = read_index_from(index_state, index_path); if (entries < 0) { @@ -625,10 +625,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co ret = WRITE_TREE_UNMERGED_INDEX; goto out; } - if (0 <= newfd) { - if (!write_locked_index(index_state, &lock_file, COMMIT_LOCK)) - newfd = -1; - } + write_locked_index(index_state, &lock_file, COMMIT_LOCK); /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller * ends up using the old index with unupdated cache-tree part @@ -650,8 +647,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co hashcpy(sha1, index_state->cache_tree->oid.hash); out: - if (0 <= newfd) - rollback_lock_file(&lock_file); + rollback_lock_file(&lock_file); return ret; } @@ -602,9 +602,28 @@ extern int do_read_index(struct index_state *istate, const char *path, extern int read_index_from(struct index_state *, const char *path); extern int is_index_unborn(struct index_state *); extern int read_index_unmerged(struct index_state *); + +/* For use with `write_locked_index()`. */ #define COMMIT_LOCK (1 << 0) -#define CLOSE_LOCK (1 << 1) + +/* + * Write the index while holding an already-taken lock. Close the lock, + * and if `COMMIT_LOCK` is given, commit it. + * + * Unless a split index is in use, write the index into the lockfile. + * + * With a split index, write the shared index to a temporary file, + * adjust its permissions and rename it into place, then write the + * split index to the lockfile. If the temporary file for the shared + * index cannot be created, fall back to the behavior described in + * the previous paragraph. + * + * With `COMMIT_LOCK`, the lock is always committed or rolled back. + * Without it, the lock is closed, but neither committed nor rolled + * back. + */ extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); + extern int discard_index(struct index_state *); extern void move_index_extensions(struct index_state *dst, struct index_state *src); extern int unmerged_index(const struct index_state *); @@ -716,6 +735,10 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg); extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int); +/* + * Opportunistically update the index but do not complain if we can't. + * The lockfile is always committed or rolled back. + */ extern void update_index_if_able(struct index_state *, struct lock_file *); extern int hold_locked_index(struct lock_file *, int); @@ -224,7 +224,7 @@ int finalize_colopts(unsigned int *colopts, int stdout_is_tty) if (stdout_is_tty < 0) stdout_is_tty = isatty(1); *colopts &= ~COL_ENABLE_MASK; - if (stdout_is_tty) + if (stdout_is_tty || pager_in_use()) *colopts |= COL_ENABLED; } return 0; diff --git a/combine-diff.c b/combine-diff.c index 9e163d5ada..82f6070977 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1014,7 +1014,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, elem->mode = canon_mode(st.st_mode); } else if (S_ISDIR(st.st_mode)) { struct object_id oid; - if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0) + if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0) result = grab_blob(&elem->oid, elem->mode, &result_size, NULL, NULL); else @@ -2751,7 +2751,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename { int ret = 0, remove = 0; char *filename_buf = NULL; - struct lock_file *lock; + struct lock_file lock = LOCK_INIT; int out_fd; char buf[1024]; FILE *config_file = NULL; @@ -2766,8 +2766,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename if (!config_filename) config_filename = filename_buf = git_pathdup("config"); - lock = xcalloc(1, sizeof(struct lock_file)); - out_fd = hold_lock_file_for_update(lock, config_filename, 0); + out_fd = hold_lock_file_for_update(&lock, config_filename, 0); if (out_fd < 0) { ret = error("could not lock config file %s", config_filename); goto out; @@ -2786,9 +2785,9 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename goto out; } - if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) { + if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) { ret = error_errno("chmod on %s failed", - get_lock_file_path(lock)); + get_lock_file_path(&lock)); goto out; } @@ -2812,7 +2811,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename */ if (copystr.len > 0) { if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) { - ret = write_error(get_lock_file_path(lock)); + ret = write_error(get_lock_file_path(&lock)); goto out; } strbuf_reset(©str); @@ -2828,7 +2827,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename store.baselen = strlen(new_name); if (!copy) { if (write_section(out_fd, new_name) < 0) { - ret = write_error(get_lock_file_path(lock)); + ret = write_error(get_lock_file_path(&lock)); goto out; } /* @@ -2862,7 +2861,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename } if (write_in_full(out_fd, output, length) < 0) { - ret = write_error(get_lock_file_path(lock)); + ret = write_error(get_lock_file_path(&lock)); goto out; } } @@ -2874,7 +2873,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename */ if (copystr.len > 0) { if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) { - ret = write_error(get_lock_file_path(lock)); + ret = write_error(get_lock_file_path(&lock)); goto out; } strbuf_reset(©str); @@ -2883,13 +2882,13 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename fclose(config_file); config_file = NULL; commit_and_out: - if (commit_lock_file(lock) < 0) + if (commit_lock_file(&lock) < 0) ret = error_errno("could not write config file %s", config_filename); out: if (config_file) fclose(config_file); - rollback_lock_file(lock); + rollback_lock_file(&lock); out_no_rollback: free(filename_buf); return ret; diff --git a/connected.c b/connected.c index f416b05051..4a47f33270 100644 --- a/connected.c +++ b/connected.c @@ -16,13 +16,13 @@ * * Returns 0 if everything is connected, non-zero otherwise. */ -int check_connected(sha1_iterate_fn fn, void *cb_data, +int check_connected(oid_iterate_fn fn, void *cb_data, struct check_connected_options *opt) { struct child_process rev_list = CHILD_PROCESS_INIT; struct check_connected_options defaults = CHECK_CONNECTED_INIT; - char commit[41]; - unsigned char sha1[20]; + char commit[GIT_MAX_HEXSZ + 1]; + struct object_id oid; int err = 0; struct packed_git *new_pack = NULL; struct transport *transport; @@ -32,7 +32,7 @@ int check_connected(sha1_iterate_fn fn, void *cb_data, opt = &defaults; transport = opt->transport; - if (fn(cb_data, sha1)) { + if (fn(cb_data, &oid)) { if (opt->err_fd) close(opt->err_fd); return err; @@ -77,7 +77,7 @@ int check_connected(sha1_iterate_fn fn, void *cb_data, sigchain_push(SIGPIPE, SIG_IGN); - commit[40] = '\n'; + commit[GIT_SHA1_HEXSZ] = '\n'; do { /* * If index-pack already checked that: @@ -87,17 +87,17 @@ int check_connected(sha1_iterate_fn fn, void *cb_data, * are sure the ref is good and not sending it to * rev-list for verification. */ - if (new_pack && find_pack_entry_one(sha1, new_pack)) + if (new_pack && find_pack_entry_one(oid.hash, new_pack)) continue; - memcpy(commit, sha1_to_hex(sha1), 40); - if (write_in_full(rev_list.in, commit, 41) < 0) { + memcpy(commit, oid_to_hex(&oid), GIT_SHA1_HEXSZ); + if (write_in_full(rev_list.in, commit, GIT_SHA1_HEXSZ + 1) < 0) { if (errno != EPIPE && errno != EINVAL) error_errno(_("failed write to rev-list")); err = -1; break; } - } while (!fn(cb_data, sha1)); + } while (!fn(cb_data, &oid)); if (close(rev_list.in)) err = error_errno(_("failed to close rev-list's stdin")); diff --git a/connected.h b/connected.h index 4ca325f79d..a53f03a61a 100644 --- a/connected.h +++ b/connected.h @@ -8,7 +8,7 @@ struct transport; * When called after returning the name for the last object, return -1 * to signal EOF, otherwise return 0. */ -typedef int (*sha1_iterate_fn)(void *, unsigned char [20]); +typedef int (*oid_iterate_fn)(void *, struct object_id *oid); /* * Named-arguments struct for check_connected. All arguments are @@ -51,7 +51,7 @@ struct check_connected_options { * * If "opt" is NULL, behaves as if CHECK_CONNECTED_INIT was passed. */ -int check_connected(sha1_iterate_fn fn, void *cb_data, +int check_connected(oid_iterate_fn fn, void *cb_data, struct check_connected_options *opt); #endif /* CONNECTED_H */ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 539d7f84f3..fdd984d34a 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2351,6 +2351,7 @@ _git_config () advice.rmHints advice.statusHints advice.statusUoption + advice.ignoredHook alias. am.keepcr am.threeWay diff --git a/diff-lib.c b/diff-lib.c index 4e0980caa8..d2ea02f4d7 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -36,7 +36,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st) if (has_symlink_leading_path(ce->name, ce_namelen(ce))) return 1; if (S_ISDIR(st->st_mode)) { - unsigned char sub[20]; + struct object_id sub; /* * If ce is already a gitlink, we can have a plain @@ -50,7 +50,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st) * a directory --- the blob was removed! */ if (!S_ISGITLINK(ce->ce_mode) && - resolve_gitlink_ref(ce->name, "HEAD", sub)) + resolve_gitlink_ref(ce->name, "HEAD", &sub)) return 1; } return 0; @@ -707,83 +707,14 @@ struct moved_entry { struct moved_entry *next_line; }; -static int next_byte(const char **cp, const char **endp, - const struct diff_options *diffopt) -{ - int retval; - - if (*cp > *endp) - return -1; - - if (isspace(**cp)) { - if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_CHANGE)) { - while (*cp < *endp && isspace(**cp)) - (*cp)++; - /* - * After skipping a couple of whitespaces, - * we still have to account for one space. - */ - return (int)' '; - } - - if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE)) { - while (*cp < *endp && isspace(**cp)) - (*cp)++; - /* return the first non-ws character via the usual below */ - } - } - - retval = (unsigned char)(**cp); - (*cp)++; - return retval; -} - static int moved_entry_cmp(const struct diff_options *diffopt, const struct moved_entry *a, const struct moved_entry *b, const void *keydata) { - const char *ap = a->es->line, *ae = a->es->line + a->es->len; - const char *bp = b->es->line, *be = b->es->line + b->es->len; - - if (!(diffopt->xdl_opts & XDF_WHITESPACE_FLAGS)) - return a->es->len != b->es->len || memcmp(ap, bp, a->es->len); - - if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_AT_EOL)) { - while (ae > ap && isspace(*ae)) - ae--; - while (be > bp && isspace(*be)) - be--; - } - - while (1) { - int ca, cb; - ca = next_byte(&ap, &ae, diffopt); - cb = next_byte(&bp, &be, diffopt); - if (ca != cb) - return 1; - if (ca < 0) - return 0; - } -} - -static unsigned get_string_hash(struct emitted_diff_symbol *es, struct diff_options *o) -{ - if (o->xdl_opts & XDF_WHITESPACE_FLAGS) { - static struct strbuf sb = STRBUF_INIT; - const char *ap = es->line, *ae = es->line + es->len; - int c; - - strbuf_reset(&sb); - while (ae > ap && isspace(*ae)) - ae--; - while ((c = next_byte(&ap, &ae, o)) > 0) - strbuf_addch(&sb, c); - - return memhash(sb.buf, sb.len); - } else { - return memhash(es->line, es->len); - } + return !xdiff_compare_lines(a->es->line, a->es->len, + b->es->line, b->es->len, + diffopt->xdl_opts); } static struct moved_entry *prepare_entry(struct diff_options *o, @@ -792,7 +723,7 @@ static struct moved_entry *prepare_entry(struct diff_options *o, struct moved_entry *ret = xmalloc(sizeof(*ret)); struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no]; - ret->ent.hash = get_string_hash(l, o); + ret->ent.hash = xdiff_hash_string(l->line, l->len, o->xdl_opts); ret->es = l; ret->next_line = NULL; @@ -180,6 +180,7 @@ struct diff_options { pathchange_fn_t pathchange; change_fn_t change; add_remove_fn_t add_remove; + void *change_fn_data; diff_format_fn_t format_callback; void *format_callback_data; diff_prefix_fn_t output_prefix; @@ -1390,9 +1390,9 @@ static enum path_treatment treat_directory(struct dir_struct *dir, if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) break; if (!(dir->flags & DIR_NO_GITLINKS)) { - unsigned char sha1[20]; - if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0) - return path_untracked; + struct object_id oid; + if (resolve_gitlink_ref(dirname, "HEAD", &oid) == 0) + return exclude ? path_excluded : path_untracked; } return path_recurse; } @@ -2279,10 +2279,10 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) int ret = 0, original_len = path->len, len, kept_down = 0; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL); - unsigned char submodule_head[20]; + struct object_id submodule_head; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && - !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) { + !resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) { /* Do not descend and nuke a nested git work tree. */ if (kept_up) *kept_up = 1; diff --git a/fast-import.c b/fast-import.c index d5e4cf0bad..b70ac025e0 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1758,7 +1758,7 @@ static int update_branch(struct branch *b) delete_ref(NULL, b->name, NULL, 0); return 0; } - if (read_ref(b->name, old_oid.hash)) + if (read_ref(b->name, &old_oid)) oidclr(&old_oid); if (!force_update && !is_null_oid(&old_oid)) { struct commit *old_cmit, *new_cmit; @@ -1778,7 +1778,7 @@ static int update_branch(struct branch *b) } transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, b->name, b->oid.hash, old_oid.hash, + ref_transaction_update(transaction, b->name, &b->oid, &old_oid, 0, msg, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@ -1820,7 +1820,7 @@ static void dump_tags(void) strbuf_addf(&ref_name, "refs/tags/%s", t->name); if (ref_transaction_update(transaction, ref_name.buf, - t->oid.hash, NULL, 0, msg, &err)) { + &t->oid, NULL, 0, msg, &err)) { failure |= error("%s", err.buf); goto cleanup; } diff --git a/git-bisect.sh b/git-bisect.sh index ae3cb013e7..0138a8860e 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -186,7 +186,7 @@ bisect_start() { # # Get rid of any old bisect state. # - bisect_clean_state || exit + git bisect--helper --bisect-clean-state || exit # # Change state. @@ -195,7 +195,7 @@ bisect_start() { # We have to trap this to be able to clean up using # "bisect_clean_state". # - trap 'bisect_clean_state' 0 + trap 'git bisect--helper --bisect-clean-state' 0 trap 'exit 255' 1 2 3 15 # @@ -209,7 +209,7 @@ bisect_start() { eval "$eval true" && if test $must_write_terms -eq 1 then - write_terms "$TERM_BAD" "$TERM_GOOD" + git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit fi && echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit # @@ -237,22 +237,6 @@ bisect_write() { test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG" } -is_expected_rev() { - test -f "$GIT_DIR/BISECT_EXPECTED_REV" && - test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV") -} - -check_expected_revs() { - for _rev in "$@"; do - if ! is_expected_rev "$_rev" - then - rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" - rm -f "$GIT_DIR/BISECT_EXPECTED_REV" - return - fi - done -} - bisect_skip() { all='' for arg in "$@" @@ -280,7 +264,7 @@ bisect_state() { rev=$(git rev-parse --verify "$bisected_head") || die "$(eval_gettext "Bad rev input: \$bisected_head")" bisect_write "$state" "$rev" - check_expected_revs "$rev" ;; + git bisect--helper --check-expected-revs "$rev" ;; 2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip) shift hash_list='' @@ -294,7 +278,7 @@ bisect_state() { do bisect_write "$state" "$rev" done - check_expected_revs $hash_list ;; + git bisect--helper --check-expected-revs $hash_list ;; *,"$TERM_BAD") die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;; *) @@ -430,27 +414,7 @@ bisect_reset() { die "$(eval_gettext "Could not check out original HEAD '\$branch'. Try 'git bisect reset <commit>'.")" fi - bisect_clean_state -} - -bisect_clean_state() { - # There may be some refs packed during bisection. - git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* | - while read ref hash - do - git update-ref -d $ref $hash || exit - done - rm -f "$GIT_DIR/BISECT_EXPECTED_REV" && - rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" && - rm -f "$GIT_DIR/BISECT_LOG" && - rm -f "$GIT_DIR/BISECT_NAMES" && - rm -f "$GIT_DIR/BISECT_RUN" && - rm -f "$GIT_DIR/BISECT_TERMS" && - # Cleanup head-name if it got left by an old version of git-bisect - rm -f "$GIT_DIR/head-name" && - git update-ref -d --no-deref BISECT_HEAD && - # clean up BISECT_START last - rm -f "$GIT_DIR/BISECT_START" + git bisect--helper --bisect-clean-state || exit } bisect_replay () { @@ -557,45 +521,6 @@ get_terms () { fi } -write_terms () { - TERM_BAD=$1 - TERM_GOOD=$2 - if test "$TERM_BAD" = "$TERM_GOOD" - then - die "$(gettext "please use two different terms")" - fi - check_term_format "$TERM_BAD" bad - check_term_format "$TERM_GOOD" good - printf '%s\n%s\n' "$TERM_BAD" "$TERM_GOOD" >"$GIT_DIR/BISECT_TERMS" -} - -check_term_format () { - term=$1 - git check-ref-format refs/bisect/"$term" || - die "$(eval_gettext "'\$term' is not a valid term")" - case "$term" in - help|start|terms|skip|next|reset|visualize|replay|log|run) - die "$(eval_gettext "can't use the builtin command '\$term' as a term")" - ;; - bad|new) - if test "$2" != bad - then - # In theory, nothing prevents swapping - # completely good and bad, but this situation - # could be confusing and hasn't been tested - # enough. Forbid it for now. - die "$(eval_gettext "can't change the meaning of term '\$term'")" - fi - ;; - good|old) - if test "$2" != good - then - die "$(eval_gettext "can't change the meaning of term '\$term'")" - fi - ;; - esac -} - check_and_set_terms () { cmd="$1" case "$cmd" in @@ -609,13 +534,17 @@ check_and_set_terms () { bad|good) if ! test -s "$GIT_DIR/BISECT_TERMS" then - write_terms bad good + TERM_BAD=bad + TERM_GOOD=good + git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit fi ;; new|old) if ! test -s "$GIT_DIR/BISECT_TERMS" then - write_terms new old + TERM_BAD=new + TERM_GOOD=old + git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit fi ;; esac ;; diff --git a/git-submodule.sh b/git-submodule.sh index 66d1ae8ef6..156255a9e5 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -758,18 +758,6 @@ cmd_update() } } -set_name_rev () { - revname=$( ( - sanitize_submodule_env - cd "$1" && { - git describe "$2" 2>/dev/null || - git describe --tags "$2" 2>/dev/null || - git describe --contains "$2" 2>/dev/null || - git describe --all --always "$2" - } - ) ) - test -z "$revname" || revname=" ($revname)" -} # # Show commit summary for submodules in index or working tree # @@ -1016,54 +1004,7 @@ cmd_status() shift done - { - git submodule--helper list --prefix "$wt_prefix" "$@" || - echo "#unmatched" $? - } | - while read -r mode sha1 stage sm_path - do - die_if_unmatched "$mode" "$sha1" - name=$(git submodule--helper name "$sm_path") || exit - displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") - if test "$stage" = U - then - say "U$sha1 $displaypath" - continue - fi - if ! git submodule--helper is-active "$sm_path" || - { - ! test -d "$sm_path"/.git && - ! test -f "$sm_path"/.git - } - then - say "-$sha1 $displaypath" - continue; - fi - if git diff-files --ignore-submodules=dirty --quiet -- "$sm_path" - then - set_name_rev "$sm_path" "$sha1" - say " $sha1 $displaypath$revname" - else - if test -z "$cached" - then - sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD) - fi - set_name_rev "$sm_path" "$sha1" - say "+$sha1 $displaypath$revname" - fi - - if test -n "$recursive" - then - ( - prefix="$displaypath/" - sanitize_submodule_env - wt_prefix= - cd "$sm_path" && - eval cmd_status - ) || - die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")" - fi - done + git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} "$@" } # # Sync remote urls for submodules diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 959f04b494..2417057f2b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -10,6 +10,8 @@ use 5.008; use strict; use warnings; +# handle ACL in file access tests +use filetest 'access'; use CGI qw(:standard :escapeHTML -nosticky); use CGI::Util qw(unescape); use CGI::Carp qw(fatalsToBrowser set_message); diff --git a/lockfile.h b/lockfile.h index 7c1c484d7c..f401c979f0 100644 --- a/lockfile.h +++ b/lockfile.h @@ -240,8 +240,8 @@ extern char *get_locked_file_path(struct lock_file *lk); * If the lockfile is still open, close it (and the file pointer if it * has been opened using `fdopen_lock_file()`) without renaming the * lockfile over the file being locked. Return 0 upon success. On - * failure to `close(2)`, return a negative value and roll back the - * lock file. Usually `commit_lock_file()`, `commit_lock_file_to()`, + * failure to `close(2)`, return a negative value (the lockfile is not + * rolled back). Usually `commit_lock_file()`, `commit_lock_file_to()`, * or `rollback_lock_file()` should eventually be called. */ static inline int close_lock_file_gently(struct lock_file *lk) diff --git a/log-tree.c b/log-tree.c index cea056234d..580b3a98a0 100644 --- a/log-tree.c +++ b/log-tree.c @@ -198,7 +198,7 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d /* Now resolve and find the matching current branch */ branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags); - if (!(rru_flags & REF_ISSYMREF)) + if (!branch_name || !(rru_flags & REF_ISSYMREF)) return NULL; if (!starts_with(branch_name, "refs/")) diff --git a/merge-recursive.c b/merge-recursive.c index 1d3f8f0d22..24c5c26a6a 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2162,7 +2162,7 @@ int merge_recursive_generic(struct merge_options *o, struct commit **result) { int clean; - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + struct lock_file lock = LOCK_INIT; struct commit *head_commit = get_ref(head, o->branch1); struct commit *next_commit = get_ref(merge, o->branch2); struct commit_list *ca = NULL; @@ -2178,14 +2178,14 @@ int merge_recursive_generic(struct merge_options *o, } } - hold_locked_index(lock, LOCK_DIE_ON_ERROR); + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (clean < 0) return clean; if (active_cache_changed && - write_locked_index(&the_index, lock, COMMIT_LOCK)) + write_locked_index(&the_index, &lock, COMMIT_LOCK)) return err(o, _("Unable to write index.")); return clean ? 0 : 1; @@ -53,11 +53,11 @@ int checkout_fast_forward(const struct object_id *head, struct tree_desc t[MAX_UNPACK_TREES]; int i, nr_trees = 0; struct dir_struct dir; - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + struct lock_file lock_file = LOCK_INIT; refresh_cache(REFRESH_QUIET); - if (hold_locked_index(lock_file, LOCK_REPORT_ON_ERROR) < 0) + if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0) return -1; memset(&trees, 0, sizeof(trees)); @@ -91,9 +91,7 @@ int checkout_fast_forward(const struct object_id *head, } if (unpack_trees(nr_trees, t, &opts)) return -1; - if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) { - rollback_lock_file(lock_file); + if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) return error(_("unable to write new index file")); - } return 0; } diff --git a/notes-cache.c b/notes-cache.c index 29b4cede5f..17ee8602b3 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -11,7 +11,7 @@ static int notes_cache_match_validity(const char *ref, const char *validity) struct strbuf msg = STRBUF_INIT; int ret; - if (read_ref(ref, oid.hash) < 0) + if (read_ref(ref, &oid) < 0) return 0; commit = lookup_commit_reference_gently(&oid, 1); @@ -59,7 +59,7 @@ int notes_cache_write(struct notes_cache *c) if (commit_tree(c->validity, strlen(c->validity), tree_oid.hash, NULL, commit_oid.hash, NULL, NULL) < 0) return -1; - if (update_ref("update notes cache", c->tree.update_ref, commit_oid.hash, + if (update_ref("update notes cache", c->tree.update_ref, &commit_oid, NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0) return -1; diff --git a/notes-merge.c b/notes-merge.c index 4352c34a6e..30ec83ab04 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -547,7 +547,7 @@ int notes_merge(struct notes_merge_options *o, o->local_ref, o->remote_ref); /* Dereference o->local_ref into local_sha1 */ - if (read_ref_full(o->local_ref, 0, local_oid.hash, NULL)) + if (read_ref_full(o->local_ref, 0, &local_oid, NULL)) die("Failed to resolve local notes ref '%s'", o->local_ref); else if (!check_refname_format(o->local_ref, 0) && is_null_oid(&local_oid)) diff --git a/notes-utils.c b/notes-utils.c index 9765deb41a..5c8e70c98f 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -18,7 +18,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, if (!parents) { /* Deduce parent commit from t->ref */ struct object_id parent_oid; - if (!read_ref(t->ref, parent_oid.hash)) { + if (!read_ref(t->ref, &parent_oid)) { struct commit *parent = lookup_commit(&parent_oid); if (parse_commit(parent)) die("Failed to find/parse commit %s", t->ref); @@ -49,7 +49,7 @@ void commit_notes(struct notes_tree *t, const char *msg) create_notes_commit(t, NULL, buf.buf, buf.len, commit_oid.hash); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ - update_ref(buf.buf, t->update_ref, commit_oid.hash, NULL, 0, + update_ref(buf.buf, t->update_ref, &commit_oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR); strbuf_release(&buf); @@ -1027,7 +1027,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref, if (flags & NOTES_INIT_EMPTY || !notes_ref || get_oid_treeish(notes_ref, &object_oid)) return; - if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_oid.hash)) + if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid)) die("Cannot use notes ref %s", notes_ref); if (get_tree_entry(object_oid.hash, "", oid.hash, &mode)) die("Failed to read notes tree referenced by %s (%s)", diff --git a/pack-bitmap.c b/pack-bitmap.c index 42e3d5f4f2..9270983e5f 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -587,7 +587,7 @@ static void show_extended_objects(struct bitmap *objects, continue; obj = eindex->objects[i]; - show_reach(obj->oid.hash, obj->type, 0, eindex->hashes[i], NULL, 0); + show_reach(&obj->oid, obj->type, 0, eindex->hashes[i], NULL, 0); } } @@ -612,7 +612,7 @@ static void show_objects_for_type( eword_t word = objects->words[i] & filter; for (offset = 0; offset < BITS_IN_EWORD; ++offset) { - const unsigned char *sha1; + struct object_id oid; struct revindex_entry *entry; uint32_t hash = 0; @@ -625,12 +625,12 @@ static void show_objects_for_type( continue; entry = &bitmap_git.pack->revindex[pos + offset]; - sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr); + nth_packed_object_oid(&oid, bitmap_git.pack, entry->nr); if (bitmap_git.hashes) hash = get_be32(bitmap_git.hashes + entry->nr); - show_reach(sha1, object_type, 0, hash, bitmap_git.pack, entry->offset); + show_reach(&oid, object_type, 0, hash, bitmap_git.pack, entry->offset); } pos += BITS_IN_EWORD; diff --git a/pack-bitmap.h b/pack-bitmap.h index 0adcef77b5..3742a00e14 100644 --- a/pack-bitmap.h +++ b/pack-bitmap.h @@ -27,7 +27,7 @@ enum pack_bitmap_flags { }; typedef int (*show_reachable_fn)( - const unsigned char *sha1, + const struct object_id *oid, enum object_type type, int flags, uint32_t hash, @@ -192,7 +192,7 @@ static void *add_to_trie(struct trie *root, const char *key, void *value) * Split this node: child will contain this node's * existing children. */ - child = malloc(sizeof(*child)); + child = xmalloc(sizeof(*child)); memcpy(child->children, root->children, sizeof(root->children)); child->len = root->len - i - 1; diff --git a/pathspec.c b/pathspec.c index cdefdc7cc0..82eb39cd67 100644 --- a/pathspec.c +++ b/pathspec.c @@ -532,7 +532,7 @@ void parse_pathspec(struct pathspec *pathspec, { struct pathspec_item *item; const char *entry = argv ? *argv : NULL; - int i, n, prefixlen, warn_empty_string, nr_exclude = 0; + int i, n, prefixlen, nr_exclude = 0; memset(pathspec, 0, sizeof(*pathspec)); @@ -565,13 +565,10 @@ void parse_pathspec(struct pathspec *pathspec, } n = 0; - warn_empty_string = 1; while (argv[n]) { - if (*argv[n] == '\0' && warn_empty_string) { - warning(_("empty strings as pathspecs will be made invalid in upcoming releases. " - "please use . instead if you meant to match all paths")); - warn_empty_string = 0; - } + if (*argv[n] == '\0') + die("empty string is not a valid pathspec. " + "please use . instead if you meant to match all paths"); n++; } @@ -11,16 +11,18 @@ # amend | esmenar # broken | malmès # delta | diferència -# dry | simulació # deprecated | en desús +# dry | simulació # fatal | fatal +# hook | lligam # hunk | tros # not supported | no està admès # repository | dipòsit +# setting | parà metre # skip | ometre # squelch | silenciar -# setting | parà metre # token | testimoni +# unset | desassignar # # Alguns termes que són comandes especÃfiques del git i d'à mbit molt tècnic # hem decidit no traduir-los per facilitar-ne la compressió a l'usuari i perquè @@ -39,6 +41,7 @@ # stage | «stage» # stash | «sta» # squash | «squash» +# trailer | «trailer» # unstage | «unstage» msgid "" msgstr "" @@ -145,7 +148,7 @@ msgstr "opció d'espai en blanc «%s» no reconeguda" #: apply.c:74 #, c-format msgid "unrecognized whitespace ignore option '%s'" -msgstr "opció d'ignora l'espai en blanc «%s» no reconeguda" +msgstr "opció ignora l'espai en blanc «%s» no reconeguda" #: apply.c:125 msgid "--reject and --3way cannot be used together." @@ -1316,7 +1319,7 @@ msgstr "memòria esgotada" #: config.c:187 msgid "relative config include conditionals must come from files" -msgstr "" +msgstr "els condicionals d'inclusió de configuració relatius han de venir de fitxers" #: config.c:721 #, c-format @@ -1432,12 +1435,12 @@ msgstr "%s no và lid: «%s»" #: config.c:2130 #, c-format msgid "unknown core.untrackedCache value '%s'; using 'keep' default value" -msgstr "" +msgstr "valor «%s» a core.untrackedCache desconegut; utilitzant el valor per defecte «keep»" #: config.c:2156 #, c-format msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100" -msgstr "" +msgstr "valor «%d» a splitIndex.maxPercentChange ha d'estar entre 0 i 100" #: config.c:2167 #, c-format @@ -1467,7 +1470,7 @@ msgstr "no s'ha pogut establir «%s» a «%s»" #: config.c:2680 builtin/remote.c:776 #, c-format msgid "could not unset '%s'" -msgstr "no s'ha pogut desestablir «%s»" +msgstr "no s'ha pogut desassignar «%s»" #: connect.c:50 msgid "The remote end hung up upon initial contact" @@ -1630,6 +1633,7 @@ msgid "" "color moved setting must be one of 'no', 'default', 'zebra', 'dimmed_zebra', " "'plain'" msgstr "" +"el parà metre de color en moviment ha de ser «no», «default», «zebra», «dimmed_zebra» o «plain»" #: diff.c:341 #, c-format @@ -2070,7 +2074,7 @@ msgstr "no s'ha pogut detectar automà ticament el nom («%s» rebut)" #: ident.c:395 #, c-format msgid "empty ident name (for <%s>) not allowed" -msgstr "" +msgstr "nom d'identitat buit (per <%s>) no és permès" #: ident.c:401 #, c-format @@ -2608,7 +2612,7 @@ msgstr "No s'ha pogut obrir «%s» per a escriptura" #: refs.c:1792 msgid "ref updates forbidden inside quarantine environment" -msgstr "" +msgstr "no està permès actualitzar les referències en un entorn de quarantena" #: refs/files-backend.c:1136 #, c-format @@ -2681,9 +2685,9 @@ msgid "%%(subject) does not take arguments" msgstr "%%(subject) no accepta parà metres" #: ref-filter.c:198 -#, fuzzy, c-format +#, c-format msgid "unknown %%(trailers) argument: %s" -msgstr "parà metre de reflexió desconegut: %s" +msgstr "parà metre %%(trailers) desconegut: %s" #: ref-filter.c:221 #, c-format @@ -3916,7 +3920,7 @@ msgstr "no s'ha pogut llegir el fitxer d'entrada «%s»" #: trailer.c:753 msgid "could not read from stdin" -msgstr "no s'ha pogut llegir des d'stdin" +msgstr "no s'ha pogut llegir des de stdin" #: trailer.c:1008 builtin/am.c:46 #, c-format @@ -4905,7 +4909,7 @@ msgstr "actualitza els fitxers seguits" #: builtin/add.c:279 msgid "record only the fact that the path will be added later" -msgstr "registra només el fet de que el camà s'afegirà més tard" +msgstr "registra només el fet que el camà s'afegirà més tard" #: builtin/add.c:280 msgid "add changes from all tracked and untracked files" @@ -4958,6 +4962,19 @@ msgid "" "\n" "See \"git help submodule\" for more information." msgstr "" +"Heu afegit un altre dipòsit git dins del dipòsit actual.\n" +"Els clons de dipòsits externs no contindran els continguts de\n" +"del dipòsit incrustat i no saben com obtenir-ho.\n" +"Si volÃeu afegir un submòdul, useu:\n" +"\n" +"\tgit submodule add <url> %s\n" +"\n" +"Si heu afegit aquest camà per error, podeu suprimir-lo de\n" +" l'Ãndex amb:\n" +"\n" +"\tgit rm --cached %s\n" +"\n" +"Vegeu \"git help submodule\" per a més informació." #: builtin/add.c:333 #, c-format @@ -5010,7 +5027,7 @@ msgstr "no s'ha pogut analitzar l'script d'autor" #: builtin/am.c:498 #, c-format msgid "'%s' was deleted by the applypatch-msg hook" -msgstr "s'ha suprimit «%s» pel ganxo applypatch-msg" +msgstr "s'ha suprimit «%s» pel lligam applypatch-msg" #: builtin/am.c:539 #, c-format @@ -5200,6 +5217,10 @@ msgid "" "such.\n" "You might run `git rm` on a file to accept \"deleted by them\" for it." msgstr "" +"Encara teniu camins sense fusionar a l'Ãndex.\n" +"Heu de fer 'git add' a cada fitxer amb conflictes resolts per marcar-los " +"com a tal.\n" +"Podeu executar `git rm` en un fitxer per acceptar \"suprimit per ells\" pel fitxer." #: builtin/am.c:2029 builtin/am.c:2033 builtin/am.c:2045 builtin/reset.c:332 #: builtin/reset.c:340 @@ -5779,7 +5800,7 @@ msgstr "canvia la informació de font" #: builtin/branch.c:588 msgid "Unset the upstream info" -msgstr "Desestableix la informació de font" +msgstr "Desassigna la informació de font" #: builtin/branch.c:589 msgid "use colored output" @@ -5945,12 +5966,12 @@ msgstr "la branca «%s» no existeix" #: builtin/branch.c:775 msgid "too many arguments to unset upstream" -msgstr "hi ha massa arguments per a desestablir la font" +msgstr "hi ha massa arguments per a desassignar la font" #: builtin/branch.c:779 msgid "could not unset upstream of HEAD when it does not point to any branch." msgstr "" -"no s'ha pogut desestablir la font de HEAD perquè no assenyala cap branca." +"no s'ha pogut desassignar la font de HEAD perquè no assenyala cap branca." #: builtin/branch.c:785 #, c-format @@ -6084,7 +6105,7 @@ msgstr "usa .gitattributes només des de l'Ãndex" #: builtin/check-attr.c:22 builtin/check-ignore.c:24 builtin/hash-object.c:99 msgid "read file names from stdin" -msgstr "llegeix els noms de fitxer d'stdin" +msgstr "llegeix els noms de fitxer de stdin" #: builtin/check-attr.c:24 builtin/check-ignore.c:26 msgid "terminate input and output records by a NUL character" @@ -6132,7 +6153,7 @@ msgstr "git check-mailmap [<opcions>] <contacte>..." #: builtin/check-mailmap.c:14 msgid "also read contacts from stdin" -msgstr "també llegeix els contactes des d'stdin" +msgstr "també llegeix els contactes des de stdin" #: builtin/check-mailmap.c:25 #, c-format @@ -6498,7 +6519,7 @@ msgstr "especificació de camà no và lida" #: builtin/checkout.c:1277 #, c-format msgid "'%s' is not a commit and a branch '%s' cannot be created from it" -msgstr "" +msgstr "«%s» no és una comissió i la branca «%s» no es pot crear a partir d'aquesta comissió" #: builtin/checkout.c:1281 #, c-format @@ -6804,7 +6825,7 @@ msgstr "clona només una branca, HEAD o --branch" #: builtin/clone.c:127 msgid "don't clone any tags, and make later fetches not to follow them" -msgstr "" +msgstr "no cloneu cap etiqueta, i feu que els «fetch» següents no els segueixen" #: builtin/clone.c:129 msgid "any cloned submodules will be shallow" @@ -7604,7 +7625,7 @@ msgstr "comet només els fitxers especificats" #: builtin/commit.c:1624 msgid "bypass pre-commit and commit-msg hooks" -msgstr "evita els ganxos de precomissió i missatge de comissió" +msgstr "evita els lligams de precomissió i missatge de comissió" #: builtin/commit.c:1625 msgid "show what would be committed" @@ -7616,7 +7637,7 @@ msgstr "esmena la comissió anterior" #: builtin/commit.c:1637 msgid "bypass post-rewrite hook" -msgstr "evita el ganxo de post escriptura" +msgstr "evita el lligam de post escriptura" #: builtin/commit.c:1642 msgid "ok to record an empty change" @@ -8067,6 +8088,8 @@ msgid "" "combined diff formats('-c' and '--cc') are not supported in\n" "directory diff mode('-d' and '--dir-diff')." msgstr "" +"els formats de diff combinats ('-c' and '--cc') no són admesos \n" +"en el mode diff per directoris ('-d' and '--dir-diff')." #: builtin/difftool.c:633 #, c-format @@ -8120,6 +8143,7 @@ msgid "" "make 'git-difftool' exit when an invoked diff tool returns a non - zero exit " "code" msgstr "" +"fes que 'git-difftool' surti quan l'eina de diff invocada torna un codi de sortida diferent a zero" #: builtin/difftool.c:715 msgid "<command>" @@ -8282,6 +8306,7 @@ msgid "" "default for recursive fetching of submodules (lower priority than config " "files)" msgstr "" +"per defecte per a l'obtenció recursiva de submòduls (prioritat més baixa que els fitxers de configuració)" #: builtin/fetch.c:156 builtin/pull.c:212 msgid "accept refs that update .git/shallow" @@ -8984,7 +9009,7 @@ msgstr "escriu l'objecte a la base de dades d'objectes" #: builtin/hash-object.c:98 msgid "read the object from stdin" -msgstr "llegeix l'objecte des d'stdin" +msgstr "llegeix l'objecte des de stdin" #: builtin/hash-object.c:100 msgid "store file as is without filters" @@ -9414,7 +9439,7 @@ msgstr "--fix-thin no es pot usar sense --stdin" #: builtin/index-pack.c:1746 msgid "--stdin requires a git repository" -msgstr "--stdin requereix d'un dipòsit git" +msgstr "--stdin requereix un dipòsit git" #: builtin/index-pack.c:1754 msgid "--verify with no packfile name given" @@ -9558,30 +9583,27 @@ msgstr "escurça els remolcs buits" #: builtin/interpret-trailers.c:96 msgid "where to place the new trailer" -msgstr "" +msgstr "on ubica" #: builtin/interpret-trailers.c:98 -#, fuzzy msgid "action if trailer already exists" -msgstr "l'arbre de treball '%s' ja existeix." +msgstr "acció si el «trailer» ja existeix" #: builtin/interpret-trailers.c:100 msgid "action if trailer is missing" -msgstr "" +msgstr "acció si el «trailer» falta" #: builtin/interpret-trailers.c:102 -#, fuzzy msgid "output only the trailers" -msgstr "escurça els remolcs buits" +msgstr "mostra només els «trailer»" #: builtin/interpret-trailers.c:103 -#, fuzzy msgid "do not apply config rules" -msgstr "cerca les variables de configuració" +msgstr "no apliquis les regles de configuració" #: builtin/interpret-trailers.c:104 msgid "join whitespace-continued values" -msgstr "" +msgstr "uneix els valors continus amb espais en blanc" #: builtin/interpret-trailers.c:105 msgid "set parsing options" @@ -9596,9 +9618,8 @@ msgid "trailer(s) to add" msgstr "remolcs a afegir" #: builtin/interpret-trailers.c:117 -#, fuzzy msgid "--trailer with --only-input does not make sense" -msgstr "--name-only no té sentit" +msgstr "--trailer amb --only-input no té sentit" #: builtin/interpret-trailers.c:127 msgid "no input file given for in-place editing" @@ -10248,9 +10269,8 @@ msgid "allow merging unrelated histories" msgstr "permet fusionar històries no relacionades" #: builtin/merge.c:240 -#, fuzzy msgid "verify commit-msg hook" -msgstr "evita els ganxos de precomissió i missatge de comissió" +msgstr "verifica el lligam de missatge de comissió" #: builtin/merge.c:265 msgid "could not run stash." @@ -10783,7 +10803,7 @@ msgstr "llista totes les comissions abastables de totes les referències" #: builtin/name-rev.c:403 msgid "read from stdin" -msgstr "llegeix d'stdin" +msgstr "llegeix de stdin" #: builtin/name-rev.c:404 msgid "allow to print `undefined` names (default)" @@ -11040,7 +11060,7 @@ msgstr "S'està eliminant la nota de l'objecte %s\n" #: builtin/notes.c:488 msgid "read objects from stdin" -msgstr "llegeix els objectes des d'stdin" +msgstr "llegeix els objectes des de stdin" #: builtin/notes.c:490 msgid "load rewriting config for <command> (implies --stdin)" @@ -11631,7 +11651,7 @@ msgstr "No es pot fer «rebase» sobre múltiples branques." #: builtin/pull.c:912 msgid "cannot rebase with locally recorded submodule modifications" -msgstr "" +msgstr "no es pot fer «rebase» amb modificacions als submòduls enregistrades localment" #: builtin/push.c:17 msgid "git push [<options>] [<repository> [<refspec>...]]" @@ -11899,7 +11919,7 @@ msgstr "poda les referències eliminades localment" #: builtin/push.c:547 msgid "bypass pre-push hook" -msgstr "evita el ganxo de prepujada" +msgstr "evita el lligam de prepujada" #: builtin/push.c:548 msgid "push missing but relevant tags" @@ -12040,13 +12060,12 @@ msgid "check the todo list" msgstr "comprova la llista a fer" #: builtin/rebase--helper.c:36 -#, fuzzy msgid "skip unnecessary picks" -msgstr "No s'ha pogut ometre ordres innecessaris d'elecció" +msgstr "omet els «picks» no necessaris" #: builtin/rebase--helper.c:38 msgid "rearrange fixup/squash lines" -msgstr "" +msgstr "reorganitza les lÃnies «fixup/pick»" #: builtin/receive-pack.c:29 msgid "git receive-pack <git-dir>" @@ -12079,7 +12098,7 @@ msgstr "" "recomana això a menys que hà giu decidit actualitzar el seu arbre en\n" "alguna altra manera per a coincidir amb el que hà giu pujat.\n" "\n" -"Per a silenciar aquest missatge i mantenir el el comportament\n" +"Per a silenciar aquest missatge i mantenir el comportament\n" "predeterminat, establiu la variable de configuració\n" "'receive.denyCurrentBranch' a 'refuse'." @@ -12645,6 +12664,8 @@ msgid "" "Incremental repacks are incompatible with bitmap indexes. Use\n" "--no-write-bitmap-index or disable the pack.writebitmaps configuration." msgstr "" +"Els re-empaquetaments incrementals són incompatibles amb els Ãndexs de bitmaps. Useu\n" +"--no-write-bitmap-index o inhabiliteu el parà metre de configuració pack.writebitmaps." #: builtin/repack.c:168 msgid "pack everything in a single pack" @@ -12906,7 +12927,7 @@ msgstr "restableix HEAD però retén els canvis locals" #: builtin/reset.c:312 msgid "record only the fact that removed paths will be added later" -msgstr "registra només el fet de que els camins eliminats s'afegiran després" +msgstr "registra només el fet que els camins eliminats s'afegiran després" #: builtin/reset.c:329 #, c-format @@ -13178,7 +13199,7 @@ msgstr "usa el protocol RPC sense estat" #: builtin/send-pack.c:177 msgid "read refs from stdin" -msgstr "llegeix les referències des d'stdin" +msgstr "llegeix les referències des de stdin" #: builtin/send-pack.c:178 msgid "print status from remote helper" @@ -13190,7 +13211,7 @@ msgstr "git shortlog [<opcions>] [<rang-de-revisions>] [[--] [<camÃ>...]]" #: builtin/shortlog.c:263 msgid "Group by committer rather than author" -msgstr "" +msgstr "Agrupa per «comiitter» en comptes de per autor" #: builtin/shortlog.c:265 msgid "sort output according to the number of commits per author" @@ -13392,7 +13413,7 @@ msgstr "no imprimeixis els resultats a stdout (útil amb --verify)" #: builtin/show-ref.c:176 msgid "show refs from stdin that aren't in local repository" -msgstr "mostra les referències d'stdin que no siguin en el dipòsit local" +msgstr "mostra les referències de stdin que no siguin en el dipòsit local" #: builtin/stripspace.c:18 msgid "git stripspace [-s | --strip-comments]" @@ -13445,6 +13466,7 @@ msgid "" "could not lookup configuration '%s'. Assuming this repository is its own " "authoritative upstream." msgstr "" +"no s'ha pogut trobar la configuració «%s». S'assumeix que aquest dipòsit és el seu dipòsit font autoritzat." #: builtin/submodule--helper.c:400 #, c-format @@ -14126,7 +14148,7 @@ msgstr "stdin té parà metres acabats amb NUL" #: builtin/update-ref.c:367 msgid "read updates from stdin" -msgstr "llegeix les actualitzacions des d'stdin" +msgstr "llegeix les actualitzacions des de stdin" #: builtin/update-server-info.c:7 msgid "git update-server-info [--force]" @@ -14209,6 +14231,8 @@ msgid "" "Removing worktrees/%s: short read (expected %<PRIuMAX> bytes, read " "%<PRIuMAX>)" msgstr "" +"S'estan suprimint els arbres de treball/%s: lectura curta (s'esperaven %<PRIuMAX> bytes, llegits " +"%<PRIuMAX>)" #: builtin/worktree.c:84 #, c-format @@ -14365,7 +14389,7 @@ msgstr "" #: http.c:338 #, c-format msgid "negative value for http.postbuffer; defaulting to %d" -msgstr "" +msgstr "valor negatiu per http.postbuffer; utilitzant el valor %d" #: http.c:359 msgid "Delegation control is not supported with cURL < 7.22.0" @@ -14793,7 +14817,7 @@ msgstr "No es pot emmagatzemar $stash_sha1" #: git-rebase.sh:214 msgid "The pre-rebase hook refused to rebase." -msgstr "El ganxo pre-«rebase» ha refusat a fer «rebase»." +msgstr "El lligam pre-«rebase» ha refusat a fer «rebase»." #: git-rebase.sh:219 msgid "It looks like git-am is in progress. Cannot rebase." @@ -15044,7 +15068,7 @@ msgstr "L'Ãndex no estava sense emmagatzemar." #: git-stash.sh:641 msgid "The stash entry is kept in case you need it again." msgstr "" -"Es conserva l'entrada «stash» en cas de que la necessiteu altra vegada." +"Es conserva l'entrada «stash» en cas que la necessiteu altra vegada." #: git-stash.sh:650 #, sh-format @@ -15489,8 +15513,8 @@ msgid "" msgstr "" "No s'ha pogut esmenar la comissió després d'escollir amb èxit $sha1... " "$rest\n" -"Això és probablement a causa d'un missatge de comissió buit, o el ganxo de\n" -"precomissió ha fallat. Si el ganxo de precomissió ha fallat, pot ser que\n" +"Això és probablement a causa d'un missatge de comissió buit, o el lligam de\n" +"precomissió ha fallat. Si el lligam de precomissió ha fallat, pot ser que\n" "necessiteu resoldre el problema abans que pugueu canviar el missatge de\n" "comissió." @@ -15741,7 +15765,7 @@ msgstr "No s'ha pogut determinar el camà absolut del directori de git" #: git-add--interactive.perl:196 #, perl-format msgid "%12s %12s %s" -msgstr "" +msgstr "%12s %12s %s" #: git-add--interactive.perl:197 msgid "staged" @@ -15955,6 +15979,12 @@ msgid "" "a - apply this hunk and all later hunks in the file\n" "d - do not apply this hunk or any of the later hunks in the file" msgstr "" +"y - aplica aquest tros a l'Ãndex\n" +"n - no apliquis aquest tros a l'Ãndex\n" +"q - surt; no apliquis aquest tros ni cap dels pendents\n" +"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n" +"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer" + #: git-add--interactive.perl:1167 msgid "" @@ -15964,6 +15994,11 @@ msgid "" "a - discard this hunk and all later hunks in the file\n" "d - do not discard this hunk or any of the later hunks in the file" msgstr "" +"y - descarta aquest tros de l'arbre de treball\n" +"n - no descartis aquest tros des de l'arbre de treball\n" +"q - surt; no apliquis aquest tros ni cap dels pendents\n" +"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n" +"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer" #: git-add--interactive.perl:1173 msgid "" @@ -15973,6 +16008,11 @@ msgid "" "a - discard this hunk and all later hunks in the file\n" "d - do not discard this hunk or any of the later hunks in the file" msgstr "" +"y - descarta aquest tros de l'Ãndex i de l'arbre de treball\n" +"n - no descartis aquest tros des de l'Ãndex i de l'arbre de treball\n" +"q - surt; no apliquis aquest tros ni cap dels pendents\n" +"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n" +"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer" #: git-add--interactive.perl:1179 msgid "" @@ -15982,6 +16022,11 @@ msgid "" "a - apply this hunk and all later hunks in the file\n" "d - do not apply this hunk or any of the later hunks in the file" msgstr "" +"y - aplica aquest tros a l'Ãndex i l'arbre de treball\n" +"n - no apliquis aquest tros des de l'Ãndex i de l'arbre de treball\n" +"q - surt; no apliquis aquest tros ni cap dels pendents\n" +"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n" +"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer" #: git-add--interactive.perl:1188 msgid "" @@ -15995,6 +16040,15 @@ msgid "" "e - manually edit the current hunk\n" "? - print help\n" msgstr "" +"g - selecciona el tros on voleu anar\n" +"/ - cerca un tros que coincideixi amb l'expressió regular donada\n" +"j - deixa aquest tros sense decidir, veure el tros sense decidir següent\n" +"J - deixa aquest tros sense decidir, veure el tros següent\n" +"k - deixa aquest tros sense decidir, veure el tros sense decidir anterior\n" +"K - deixa aquest tros sense decidir, veure el tros anterior\n" +"s - divideix el tros actual en trossos més petits\n" +"e - edita manualment el tros actual\n" +"? - mostra l'ajuda\n" #: git-add--interactive.perl:1219 msgid "The selected hunks do not apply to the index!\n" @@ -16200,6 +16254,12 @@ msgid "" "add untracked - add contents of untracked files to the staged set of " "changes\n" msgstr "" +"status - mostra els camins amb canvis\n" +"update - afegeix l'estat de l'arbre de treball al conjunt de canvis «staged»\n" +"revert - reverteix el conjunt de canvis de «staged» a la versió HEAD\n" +"patch - selecciona trossos i actualitza'ls selectivament\n" +"diff - mostra la diferència entre HEAD i l'Ãndex\n" +"add untracked - afegeix el contingut dels fitxers no seguits al conjunt de canvis «staged»\n" #: git-add--interactive.perl:1641 git-add--interactive.perl:1646 #: git-add--interactive.perl:1649 git-add--interactive.perl:1656 @@ -16386,6 +16446,11 @@ msgid "" "want to send.\n" msgstr "" +"S'ha refusat a enviar perquè el pedaç\n" +"\t%s\n" +"perquè la plantilla té l'assumpte '*** SUBJECT HERE ***'. Passeu --force si realment " +"voleu enviar-lo.\n" + #: git-send-email.perl:847 msgid "To whom should the emails be sent (if anyone)?" msgstr "" @@ -16466,7 +16531,7 @@ msgstr "El servidor no admet STARTTLS! %s" #: git-send-email.perl:1431 git-send-email.perl:1435 #, perl-format msgid "STARTTLS failed! %s" -msgstr "" +msgstr "STARTTLS ha fallat! %s" #: git-send-email.perl:1445 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug." diff --git a/read-cache.c b/read-cache.c index 65f4fe8375..f3d125c114 100644 --- a/read-cache.c +++ b/read-cache.c @@ -191,7 +191,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size) static int ce_compare_gitlink(const struct cache_entry *ce) { - unsigned char sha1[20]; + struct object_id oid; /* * We don't actually require that the .git directory @@ -201,9 +201,9 @@ static int ce_compare_gitlink(const struct cache_entry *ce) * * If so, we consider it always to match. */ - if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0) + if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0) return 0; - return hashcmp(sha1, ce->oid.hash); + return oidcmp(&oid, &ce->oid); } static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st) @@ -2176,17 +2176,22 @@ static int has_racy_timestamp(struct index_state *istate) return 0; } -/* - * Opportunistically update the index but do not complain if we can't - */ void update_index_if_able(struct index_state *istate, struct lock_file *lockfile) { if ((istate->cache_changed || has_racy_timestamp(istate)) && - verify_index(istate) && - write_locked_index(istate, lockfile, COMMIT_LOCK)) + verify_index(istate)) + write_locked_index(istate, lockfile, COMMIT_LOCK); + else rollback_lock_file(lockfile); } +/* + * On success, `tempfile` is closed. If it is the temporary file + * of a `struct lock_file`, we will therefore effectively perform + * a 'close_lock_file_gently()`. Since that is an implementation + * detail of lockfiles, callers of `do_write_index()` should not + * rely on it. + */ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, int strip_extensions) { @@ -2314,7 +2319,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, return -1; if (close_tempfile_gently(tempfile)) { error(_("could not close '%s'"), tempfile->filename.buf); - delete_tempfile(&tempfile); return -1; } if (stat(tempfile->filename.buf, &st)) @@ -2343,14 +2347,9 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l int ret = do_write_index(istate, lock->tempfile, 0); if (ret) return ret; - assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) != - (COMMIT_LOCK | CLOSE_LOCK)); if (flags & COMMIT_LOCK) return commit_locked_index(lock); - else if (flags & CLOSE_LOCK) - return close_lock_file_gently(lock); - else - return ret; + return close_lock_file_gently(lock); } static int write_split_index(struct index_state *istate, @@ -2499,7 +2498,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, (istate->cache_changed & ~EXTMASK)) { if (si) hashclr(si->base_sha1); - return do_write_locked_index(istate, lock, flags); + ret = do_write_locked_index(istate, lock, flags); + goto out; } if (getenv("GIT_TEST_SPLIT_INDEX")) { @@ -2515,7 +2515,7 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, if (new_shared_index) { ret = write_shared_index(istate, lock, flags); if (ret) - return ret; + goto out; } ret = write_split_index(istate, lock, flags); @@ -2524,6 +2524,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, if (!ret && !new_shared_index) freshen_shared_index(sha1_to_hex(si->base_sha1), 1); +out: + if (flags & COMMIT_LOCK) + rollback_lock_file(lock); return ret; } diff --git a/reflog-walk.c b/reflog-walk.c index 842b2f77dc..5008bbf6ad 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -161,7 +161,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info, struct object_id oid; char *b; int ret = dwim_log(branch, strlen(branch), - oid.hash, &b); + &oid, &b); if (ret > 1) free(b); else if (ret == 1) { @@ -194,21 +194,21 @@ int ref_resolves_to_object(const char *refname, char *refs_resolve_refdup(struct ref_store *refs, const char *refname, int resolve_flags, - unsigned char *sha1, int *flags) + struct object_id *oid, int *flags) { const char *result; result = refs_resolve_ref_unsafe(refs, refname, resolve_flags, - sha1, flags); + oid, flags); return xstrdup_or_null(result); } char *resolve_refdup(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags) + struct object_id *oid, int *flags) { return refs_resolve_refdup(get_main_ref_store(), refname, resolve_flags, - sha1, flags); + oid, flags); } /* The argument to filter_refs */ @@ -219,22 +219,22 @@ struct ref_filter { }; int refs_read_ref_full(struct ref_store *refs, const char *refname, - int resolve_flags, unsigned char *sha1, int *flags) + int resolve_flags, struct object_id *oid, int *flags) { - if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, sha1, flags)) + if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, oid, flags)) return 0; return -1; } -int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags) +int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags) { return refs_read_ref_full(get_main_ref_store(), refname, - resolve_flags, sha1, flags); + resolve_flags, oid, flags); } -int read_ref(const char *refname, unsigned char *sha1) +int read_ref(const char *refname, struct object_id *oid) { - return read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL); + return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL); } int ref_exists(const char *refname) @@ -252,12 +252,12 @@ static int filter_refs(const char *refname, const struct object_id *oid, return filter->fn(refname, oid, flags, filter->cb_data); } -enum peel_status peel_object(const unsigned char *name, unsigned char *sha1) +enum peel_status peel_object(const struct object_id *name, struct object_id *oid) { - struct object *o = lookup_unknown_object(name); + struct object *o = lookup_unknown_object(name->hash); if (o->type == OBJ_NONE) { - int type = sha1_object_info(name, NULL); + int type = sha1_object_info(name->hash, NULL); if (type < 0 || !object_as_type(o, type, 0)) return PEEL_INVALID; } @@ -269,7 +269,7 @@ enum peel_status peel_object(const unsigned char *name, unsigned char *sha1) if (!o) return PEEL_INVALID; - hashcpy(sha1, o->oid.hash); + oidcpy(oid, &o->oid); return PEEL_PEELED; } @@ -362,7 +362,7 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data) int flag; strbuf_addf(&buf, "%sHEAD", get_git_namespace()); - if (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag)) + if (!read_ref_full(buf.buf, RESOLVE_REF_READING, &oid, &flag)) ret = fn(buf.buf, &oid, flag, cb_data); strbuf_release(&buf); @@ -456,15 +456,15 @@ static char *substitute_branch_name(const char **string, int *len) return NULL; } -int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) +int dwim_ref(const char *str, int len, struct object_id *oid, char **ref) { char *last_branch = substitute_branch_name(&str, &len); - int refs_found = expand_ref(str, len, sha1, ref); + int refs_found = expand_ref(str, len, oid, ref); free(last_branch); return refs_found; } -int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) +int expand_ref(const char *str, int len, struct object_id *oid, char **ref) { const char **p, *r; int refs_found = 0; @@ -472,11 +472,11 @@ int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { - unsigned char sha1_from_ref[20]; - unsigned char *this_result; + struct object_id oid_from_ref; + struct object_id *this_result; int flag; - this_result = refs_found ? sha1_from_ref : sha1; + this_result = refs_found ? &oid_from_ref : oid; strbuf_reset(&fullref); strbuf_addf(&fullref, *p, len, str); r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING, @@ -496,7 +496,7 @@ int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) return refs_found; } -int dwim_log(const char *str, int len, unsigned char *sha1, char **log) +int dwim_log(const char *str, int len, struct object_id *oid, char **log) { char *last_branch = substitute_branch_name(&str, &len); const char **p; @@ -505,13 +505,13 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { - unsigned char hash[20]; + struct object_id hash; const char *ref, *it; strbuf_reset(&path); strbuf_addf(&path, *p, len, str); ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING, - hash, NULL); + &hash, NULL); if (!ref) continue; if (reflog_exists(path.buf)) @@ -522,7 +522,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) continue; if (!logs_found++) { *log = xstrdup(it); - hashcpy(sha1, hash); + oidcpy(oid, &hash); } if (!warn_ambiguous_refs) break; @@ -574,8 +574,8 @@ long get_files_ref_lock_timeout_ms(void) return timeout_ms; } -static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, - const unsigned char *old_sha1, struct strbuf *err) +static int write_pseudoref(const char *pseudoref, const struct object_id *oid, + const struct object_id *old_oid, struct strbuf *err) { const char *filename; int fd; @@ -583,7 +583,10 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, struct strbuf buf = STRBUF_INIT; int ret = -1; - strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1)); + if (!oid) + return 0; + + strbuf_addf(&buf, "%s\n", oid_to_hex(oid)); filename = git_path("%s", pseudoref); fd = hold_lock_file_for_update_timeout(&lock, filename, @@ -595,12 +598,12 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, goto done; } - if (old_sha1) { - unsigned char actual_old_sha1[20]; + if (old_oid) { + struct object_id actual_old_oid; - if (read_ref(pseudoref, actual_old_sha1)) + if (read_ref(pseudoref, &actual_old_oid)) die("could not read ref '%s'", pseudoref); - if (hashcmp(actual_old_sha1, old_sha1)) { + if (oidcmp(&actual_old_oid, old_oid)) { strbuf_addf(err, "unexpected sha1 when writing '%s'", pseudoref); rollback_lock_file(&lock); goto done; @@ -620,25 +623,25 @@ done: return ret; } -static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1) +static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid) { static struct lock_file lock; const char *filename; filename = git_path("%s", pseudoref); - if (old_sha1 && !is_null_sha1(old_sha1)) { + if (old_oid && !is_null_oid(old_oid)) { int fd; - unsigned char actual_old_sha1[20]; + struct object_id actual_old_oid; fd = hold_lock_file_for_update_timeout( &lock, filename, LOCK_DIE_ON_ERROR, get_files_ref_lock_timeout_ms()); if (fd < 0) die_errno(_("Could not open '%s' for writing"), filename); - if (read_ref(pseudoref, actual_old_sha1)) + if (read_ref(pseudoref, &actual_old_oid)) die("could not read ref '%s'", pseudoref); - if (hashcmp(actual_old_sha1, old_sha1)) { + if (oidcmp(&actual_old_oid, old_oid)) { warning("Unexpected sha1 when deleting %s", pseudoref); rollback_lock_file(&lock); return -1; @@ -655,7 +658,7 @@ static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1 int refs_delete_ref(struct ref_store *refs, const char *msg, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags) { struct ref_transaction *transaction; @@ -663,12 +666,12 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, if (ref_type(refname) == REF_TYPE_PSEUDOREF) { assert(refs == get_main_ref_store()); - return delete_pseudoref(refname, old_sha1); + return delete_pseudoref(refname, old_oid); } transaction = ref_store_transaction_begin(refs, &err); if (!transaction || - ref_transaction_delete(transaction, refname, old_sha1, + ref_transaction_delete(transaction, refname, old_oid, flags, msg, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); @@ -682,10 +685,10 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, } int delete_ref(const char *msg, const char *refname, - const unsigned char *old_sha1, unsigned int flags) + const struct object_id *old_oid, unsigned int flags) { return refs_delete_ref(get_main_ref_store(), msg, refname, - old_sha1, flags); + old_oid, flags); } int copy_reflog_msg(char *buf, const char *msg) @@ -734,11 +737,11 @@ struct read_ref_at_cb { timestamp_t at_time; int cnt; int reccnt; - unsigned char *sha1; + struct object_id *oid; int found_it; - unsigned char osha1[20]; - unsigned char nsha1[20]; + struct object_id ooid; + struct object_id noid; int tz; timestamp_t date; char **msg; @@ -770,25 +773,25 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, * we have not yet updated cb->[n|o]sha1 so they still * hold the values for the previous record. */ - if (!is_null_sha1(cb->osha1)) { - hashcpy(cb->sha1, noid->hash); - if (hashcmp(cb->osha1, noid->hash)) + if (!is_null_oid(&cb->ooid)) { + oidcpy(cb->oid, noid); + if (oidcmp(&cb->ooid, noid)) warning("Log for ref %s has gap after %s.", cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); } else if (cb->date == cb->at_time) - hashcpy(cb->sha1, noid->hash); - else if (hashcmp(noid->hash, cb->sha1)) + oidcpy(cb->oid, noid); + else if (oidcmp(noid, cb->oid)) warning("Log for ref %s unexpectedly ended on %s.", cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); - hashcpy(cb->osha1, ooid->hash); - hashcpy(cb->nsha1, noid->hash); + oidcpy(&cb->ooid, ooid); + oidcpy(&cb->noid, noid); cb->found_it = 1; return 1; } - hashcpy(cb->osha1, ooid->hash); - hashcpy(cb->nsha1, noid->hash); + oidcpy(&cb->ooid, ooid); + oidcpy(&cb->noid, noid); if (cb->cnt > 0) cb->cnt--; return 0; @@ -808,15 +811,15 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid *cb->cutoff_tz = tz; if (cb->cutoff_cnt) *cb->cutoff_cnt = cb->reccnt; - hashcpy(cb->sha1, ooid->hash); - if (is_null_sha1(cb->sha1)) - hashcpy(cb->sha1, noid->hash); + oidcpy(cb->oid, ooid); + if (is_null_oid(cb->oid)) + oidcpy(cb->oid, noid); /* We just want the first entry */ return 1; } int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt, - unsigned char *sha1, char **msg, + struct object_id *oid, char **msg, timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt) { struct read_ref_at_cb cb; @@ -829,7 +832,7 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in cb.cutoff_time = cutoff_time; cb.cutoff_tz = cutoff_tz; cb.cutoff_cnt = cutoff_cnt; - cb.sha1 = sha1; + cb.oid = oid; for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb); @@ -894,8 +897,8 @@ void ref_transaction_free(struct ref_transaction *transaction) struct ref_update *ref_transaction_add_update( struct ref_transaction *transaction, const char *refname, unsigned int flags, - const unsigned char *new_sha1, - const unsigned char *old_sha1, + const struct object_id *new_oid, + const struct object_id *old_oid, const char *msg) { struct ref_update *update; @@ -913,23 +916,23 @@ struct ref_update *ref_transaction_add_update( update->flags = flags; if (flags & REF_HAVE_NEW) - hashcpy(update->new_oid.hash, new_sha1); + oidcpy(&update->new_oid, new_oid); if (flags & REF_HAVE_OLD) - hashcpy(update->old_oid.hash, old_sha1); + oidcpy(&update->old_oid, old_oid); update->msg = xstrdup_or_null(msg); return update; } int ref_transaction_update(struct ref_transaction *transaction, const char *refname, - const unsigned char *new_sha1, - const unsigned char *old_sha1, + const struct object_id *new_oid, + const struct object_id *old_oid, unsigned int flags, const char *msg, struct strbuf *err) { assert(err); - if ((new_sha1 && !is_null_sha1(new_sha1)) ? + if ((new_oid && !is_null_oid(new_oid)) ? check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : !refname_is_safe(refname)) { strbuf_addf(err, "refusing to update ref with bad name '%s'", @@ -939,62 +942,54 @@ int ref_transaction_update(struct ref_transaction *transaction, flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS; - flags |= (new_sha1 ? REF_HAVE_NEW : 0) | (old_sha1 ? REF_HAVE_OLD : 0); + flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0); ref_transaction_add_update(transaction, refname, flags, - new_sha1, old_sha1, msg); + new_oid, old_oid, msg); return 0; } int ref_transaction_create(struct ref_transaction *transaction, const char *refname, - const unsigned char *new_sha1, + const struct object_id *new_oid, unsigned int flags, const char *msg, struct strbuf *err) { - if (!new_sha1 || is_null_sha1(new_sha1)) - die("BUG: create called without valid new_sha1"); - return ref_transaction_update(transaction, refname, new_sha1, - null_sha1, flags, msg, err); + if (!new_oid || is_null_oid(new_oid)) + die("BUG: create called without valid new_oid"); + return ref_transaction_update(transaction, refname, new_oid, + &null_oid, flags, msg, err); } int ref_transaction_delete(struct ref_transaction *transaction, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags, const char *msg, struct strbuf *err) { - if (old_sha1 && is_null_sha1(old_sha1)) - die("BUG: delete called with old_sha1 set to zeros"); + if (old_oid && is_null_oid(old_oid)) + die("BUG: delete called with old_oid set to zeros"); return ref_transaction_update(transaction, refname, - null_sha1, old_sha1, + &null_oid, old_oid, flags, msg, err); } int ref_transaction_verify(struct ref_transaction *transaction, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags, struct strbuf *err) { - if (!old_sha1) - die("BUG: verify called with old_sha1 set to NULL"); + if (!old_oid) + die("BUG: verify called with old_oid set to NULL"); return ref_transaction_update(transaction, refname, - NULL, old_sha1, + NULL, old_oid, flags, NULL, err); } -int update_ref_oid(const char *msg, const char *refname, - const struct object_id *new_oid, const struct object_id *old_oid, - unsigned int flags, enum action_on_err onerr) -{ - return update_ref(msg, refname, new_oid ? new_oid->hash : NULL, - old_oid ? old_oid->hash : NULL, flags, onerr); -} - int refs_update_ref(struct ref_store *refs, const char *msg, - const char *refname, const unsigned char *new_sha1, - const unsigned char *old_sha1, unsigned int flags, + const char *refname, const struct object_id *new_oid, + const struct object_id *old_oid, unsigned int flags, enum action_on_err onerr) { struct ref_transaction *t = NULL; @@ -1003,11 +998,11 @@ int refs_update_ref(struct ref_store *refs, const char *msg, if (ref_type(refname) == REF_TYPE_PSEUDOREF) { assert(refs == get_main_ref_store()); - ret = write_pseudoref(refname, new_sha1, old_sha1, &err); + ret = write_pseudoref(refname, new_oid, old_oid, &err); } else { t = ref_store_transaction_begin(refs, &err); if (!t || - ref_transaction_update(t, refname, new_sha1, old_sha1, + ref_transaction_update(t, refname, new_oid, old_oid, flags, msg, &err) || ref_transaction_commit(t, &err)) { ret = 1; @@ -1037,12 +1032,12 @@ int refs_update_ref(struct ref_store *refs, const char *msg, } int update_ref(const char *msg, const char *refname, - const unsigned char *new_sha1, - const unsigned char *old_sha1, + const struct object_id *new_oid, + const struct object_id *old_oid, unsigned int flags, enum action_on_err onerr) { - return refs_update_ref(get_main_ref_store(), msg, refname, new_sha1, - old_sha1, flags, onerr); + return refs_update_ref(get_main_ref_store(), msg, refname, new_oid, + old_oid, flags, onerr); } char *shorten_unambiguous_ref(const char *refname, int strict) @@ -1254,7 +1249,7 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int flag; if (!refs_read_ref_full(refs, "HEAD", RESOLVE_REF_READING, - oid.hash, &flag)) + &oid, &flag)) return fn("HEAD", &oid, flag, cb_data); return 0; @@ -1387,25 +1382,25 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) } int refs_read_raw_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1, + const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type) { - return ref_store->be->read_raw_ref(ref_store, refname, sha1, referent, type); + return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, type); } /* This function needs to return a meaningful errno on failure */ const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, int resolve_flags, - unsigned char *sha1, int *flags) + struct object_id *oid, int *flags) { static struct strbuf sb_refname = STRBUF_INIT; struct object_id unused_oid; int unused_flags; int symref_count; - if (!sha1) - sha1 = unused_oid.hash; + if (!oid) + oid = &unused_oid; if (!flags) flags = &unused_flags; @@ -1433,7 +1428,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, unsigned int read_flags = 0; if (refs_read_raw_ref(refs, refname, - sha1, &sb_refname, &read_flags)) { + oid, &sb_refname, &read_flags)) { *flags |= read_flags; /* In reading mode, refs must eventually resolve */ @@ -1450,7 +1445,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, errno != ENOTDIR) return NULL; - hashclr(sha1); + oidclr(oid); if (*flags & REF_BAD_NAME) *flags |= REF_ISBROKEN; return refname; @@ -1460,7 +1455,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, if (!(read_flags & REF_ISSYMREF)) { if (*flags & REF_BAD_NAME) { - hashclr(sha1); + oidclr(oid); *flags |= REF_ISBROKEN; } return refname; @@ -1468,7 +1463,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, refname = sb_refname.buf; if (resolve_flags & RESOLVE_REF_NO_RECURSE) { - hashclr(sha1); + oidclr(oid); return refname; } if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { @@ -1495,14 +1490,14 @@ int refs_init_db(struct strbuf *err) } const char *resolve_ref_unsafe(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags) + struct object_id *oid, int *flags) { return refs_resolve_ref_unsafe(get_main_ref_store(), refname, - resolve_flags, sha1, flags); + resolve_flags, oid, flags); } int resolve_gitlink_ref(const char *submodule, const char *refname, - unsigned char *sha1) + struct object_id *oid) { struct ref_store *refs; int flags; @@ -1512,8 +1507,8 @@ int resolve_gitlink_ref(const char *submodule, const char *refname, if (!refs) return -1; - if (!refs_resolve_ref_unsafe(refs, refname, 0, sha1, &flags) || - is_null_sha1(sha1)) + if (!refs_resolve_ref_unsafe(refs, refname, 0, oid, &flags) || + is_null_oid(oid)) return -1; return 0; } @@ -1701,30 +1696,30 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags) } int refs_peel_ref(struct ref_store *refs, const char *refname, - unsigned char *sha1) + struct object_id *oid) { int flag; - unsigned char base[20]; + struct object_id base; if (current_ref_iter && current_ref_iter->refname == refname) { struct object_id peeled; if (ref_iterator_peel(current_ref_iter, &peeled)) return -1; - hashcpy(sha1, peeled.hash); + oidcpy(oid, &peeled); return 0; } if (refs_read_ref_full(refs, refname, - RESOLVE_REF_READING, base, &flag)) + RESOLVE_REF_READING, &base, &flag)) return -1; - return peel_object(base, sha1); + return peel_object(&base, oid); } -int peel_ref(const char *refname, unsigned char *sha1) +int peel_ref(const char *refname, struct object_id *oid) { - return refs_peel_ref(get_main_ref_store(), refname, sha1); + return refs_peel_ref(get_main_ref_store(), refname, oid); } int refs_create_symref(struct ref_store *refs, @@ -1884,7 +1879,7 @@ int refs_verify_refname_available(struct ref_store *refs, if (skip && string_list_has_string(skip, dirname.buf)) continue; - if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) { + if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) { strbuf_addf(err, "'%s' exists; cannot create '%s'", dirname.buf, refname); goto cleanup; @@ -2014,19 +2009,19 @@ int delete_reflog(const char *refname) } int refs_reflog_expire(struct ref_store *refs, - const char *refname, const unsigned char *sha1, + const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, reflog_expiry_cleanup_fn cleanup_fn, void *policy_cb_data) { - return refs->be->reflog_expire(refs, refname, sha1, flags, + return refs->be->reflog_expire(refs, refname, oid, flags, prepare_fn, should_prune_fn, cleanup_fn, policy_cb_data); } -int reflog_expire(const char *refname, const unsigned char *sha1, +int reflog_expire(const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, @@ -2034,7 +2029,7 @@ int reflog_expire(const char *refname, const unsigned char *sha1, void *policy_cb_data) { return refs_reflog_expire(get_main_ref_store(), - refname, sha1, flags, + refname, oid, flags, prepare_fn, should_prune_fn, cleanup_fn, policy_cb_data); } @@ -14,22 +14,22 @@ struct worktree; * at the resolved object name. The return value, if not NULL, is a * pointer into either a static buffer or the input ref. * - * If sha1 is non-NULL, store the referred-to object's name in it. + * If oid is non-NULL, store the referred-to object's name in it. * * If the reference cannot be resolved to an object, the behavior * depends on the RESOLVE_REF_READING flag: * * - If RESOLVE_REF_READING is set, return NULL. * - * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of + * - If RESOLVE_REF_READING is not set, clear oid and return the name of * the last reference name in the chain, which will either be a non-symbolic * reference or an undefined reference. If this is a prelude to * "writing" to the ref, the return value is the name of the ref * that will actually be created or changed. * * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one - * level of symbolic reference. The value stored in sha1 for a symbolic - * reference will always be null_sha1 in this case, and the return + * level of symbolic reference. The value stored in oid for a symbolic + * reference will always be null_oid in this case, and the return * value is the reference that the symref refers to directly. * * If flags is non-NULL, set the value that it points to the @@ -46,7 +46,7 @@ struct worktree; * * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their * name is invalid according to git-check-ref-format(1). If the name - * is bad then the value stored in sha1 will be null_sha1 and the two + * is bad then the value stored in oid will be null_oid and the two * flags REF_ISBROKEN and REF_BAD_NAME will be set. * * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/ @@ -62,22 +62,22 @@ struct worktree; const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, int resolve_flags, - unsigned char *sha1, + struct object_id *oid, int *flags); const char *resolve_ref_unsafe(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags); + struct object_id *oid, int *flags); char *refs_resolve_refdup(struct ref_store *refs, const char *refname, int resolve_flags, - unsigned char *sha1, int *flags); + struct object_id *oid, int *flags); char *resolve_refdup(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags); + struct object_id *oid, int *flags); int refs_read_ref_full(struct ref_store *refs, const char *refname, - int resolve_flags, unsigned char *sha1, int *flags); + int resolve_flags, struct object_id *oid, int *flags); int read_ref_full(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags); -int read_ref(const char *refname, unsigned char *sha1); + struct object_id *oid, int *flags); +int read_ref(const char *refname, struct object_id *oid); /* * Return 0 if a reference named refname could be created without @@ -114,14 +114,14 @@ extern int refs_init_db(struct strbuf *err); /* * If refname is a non-symbolic reference that refers to a tag object, * and the tag can be (recursively) dereferenced to a non-tag object, - * store the SHA1 of the referred-to object to sha1 and return 0. If - * any of these conditions are not met, return a non-zero value. + * store the object ID of the referred-to object to oid and return 0. + * If any of these conditions are not met, return a non-zero value. * Symbolic references are considered unpeelable, even if they * ultimately resolve to a peelable tag. */ int refs_peel_ref(struct ref_store *refs, const char *refname, - unsigned char *sha1); -int peel_ref(const char *refname, unsigned char *sha1); + struct object_id *oid); +int peel_ref(const char *refname, struct object_id *oid); /** * Resolve refname in the nested "gitlink" repository in the specified @@ -130,7 +130,7 @@ int peel_ref(const char *refname, unsigned char *sha1); * otherwise, return a non-zero value. */ int resolve_gitlink_ref(const char *submodule, const char *refname, - unsigned char *sha1); + struct object_id *oid); /* * Return true iff abbrev_name is a possible abbreviation for @@ -139,9 +139,9 @@ int resolve_gitlink_ref(const char *submodule, const char *refname, */ int refname_match(const char *abbrev_name, const char *full_name); -int expand_ref(const char *str, int len, unsigned char *sha1, char **ref); -int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref); -int dwim_log(const char *str, int len, unsigned char *sha1, char **ref); +int expand_ref(const char *str, int len, struct object_id *oid, char **ref); +int dwim_ref(const char *str, int len, struct object_id *oid, char **ref); +int dwim_log(const char *str, int len, struct object_id *oid, char **ref); /* * A ref_transaction represents a collection of reference updates that @@ -363,7 +363,7 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err /** Reads log for the value of ref during at_time. **/ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt, - unsigned char *sha1, char **msg, + struct object_id *oid, char **msg, timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt); /** Check if a particular reflog exists */ @@ -371,19 +371,19 @@ int refs_reflog_exists(struct ref_store *refs, const char *refname); int reflog_exists(const char *refname); /* - * Delete the specified reference. If old_sha1 is non-NULL, then + * Delete the specified reference. If old_oid is non-NULL, then * verify that the current value of the reference is old_sha1 before - * deleting it. If old_sha1 is NULL, delete the reference if it - * exists, regardless of its old value. It is an error for old_sha1 to - * be NULL_SHA1. msg and flags are passed through to + * deleting it. If old_oid is NULL, delete the reference if it + * exists, regardless of its old value. It is an error for old_oid to + * be null_oid. msg and flags are passed through to * ref_transaction_delete(). */ int refs_delete_ref(struct ref_store *refs, const char *msg, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags); int delete_ref(const char *msg, const char *refname, - const unsigned char *old_sha1, unsigned int flags); + const struct object_id *old_oid, unsigned int flags); /* * Delete the specified references. If there are any problems, emit @@ -511,14 +511,14 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err); */ /* - * Add a reference update to transaction. new_sha1 is the value that - * the reference should have after the update, or null_sha1 if it - * should be deleted. If new_sha1 is NULL, then the reference is not - * changed at all. old_sha1 is the value that the reference must have - * before the update, or null_sha1 if it must not have existed + * Add a reference update to transaction. new_oid is the value that + * the reference should have after the update, or null_oid if it + * should be deleted. If new_oid is NULL, then the reference is not + * changed at all. old_oid is the value that the reference must have + * before the update, or null_oid if it must not have existed * beforehand. The old value is checked after the lock is taken to - * prevent races. If the old value doesn't agree with old_sha1, the - * whole transaction fails. If old_sha1 is NULL, then the previous + * prevent races. If the old value doesn't agree with old_oid, the + * whole transaction fails. If old_oid is NULL, then the previous * value is not checked. * * See the above comment "Reference transaction updates" for more @@ -526,15 +526,15 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err); */ int ref_transaction_update(struct ref_transaction *transaction, const char *refname, - const unsigned char *new_sha1, - const unsigned char *old_sha1, + const struct object_id *new_oid, + const struct object_id *old_oid, unsigned int flags, const char *msg, struct strbuf *err); /* - * Add a reference creation to transaction. new_sha1 is the value that + * Add a reference creation to transaction. new_oid is the value that * the reference should have after the update; it must not be - * null_sha1. It is verified that the reference does not exist + * null_oid. It is verified that the reference does not exist * already. * * See the above comment "Reference transaction updates" for more @@ -542,35 +542,35 @@ int ref_transaction_update(struct ref_transaction *transaction, */ int ref_transaction_create(struct ref_transaction *transaction, const char *refname, - const unsigned char *new_sha1, + const struct object_id *new_oid, unsigned int flags, const char *msg, struct strbuf *err); /* - * Add a reference deletion to transaction. If old_sha1 is non-NULL, + * Add a reference deletion to transaction. If old_oid is non-NULL, * then it holds the value that the reference should have had before - * the update (which must not be null_sha1). + * the update (which must not be null_oid). * * See the above comment "Reference transaction updates" for more * information. */ int ref_transaction_delete(struct ref_transaction *transaction, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags, const char *msg, struct strbuf *err); /* - * Verify, within a transaction, that refname has the value old_sha1, - * or, if old_sha1 is null_sha1, then verify that the reference - * doesn't exist. old_sha1 must be non-NULL. + * Verify, within a transaction, that refname has the value old_oid, + * or, if old_oid is null_oid, then verify that the reference + * doesn't exist. old_oid must be non-NULL. * * See the above comment "Reference transaction updates" for more * information. */ int ref_transaction_verify(struct ref_transaction *transaction, const char *refname, - const unsigned char *old_sha1, + const struct object_id *old_oid, unsigned int flags, struct strbuf *err); @@ -643,12 +643,9 @@ void ref_transaction_free(struct ref_transaction *transaction); * argument. */ int refs_update_ref(struct ref_store *refs, const char *msg, const char *refname, - const unsigned char *new_sha1, const unsigned char *old_sha1, + const struct object_id *new_oid, const struct object_id *old_oid, unsigned int flags, enum action_on_err onerr); int update_ref(const char *msg, const char *refname, - const unsigned char *new_sha1, const unsigned char *old_sha1, - unsigned int flags, enum action_on_err onerr); -int update_ref_oid(const char *msg, const char *refname, const struct object_id *new_oid, const struct object_id *old_oid, unsigned int flags, enum action_on_err onerr); @@ -706,20 +703,20 @@ typedef int reflog_expiry_should_prune_fn(struct object_id *ooid, typedef void reflog_expiry_cleanup_fn(void *cb_data); /* - * Expire reflog entries for the specified reference. sha1 is the old + * Expire reflog entries for the specified reference. oid is the old * value of the reference. flags is a combination of the constants in * enum expire_reflog_flags. The three function pointers are described * above. On success, return zero. */ int refs_reflog_expire(struct ref_store *refs, const char *refname, - const unsigned char *sha1, + const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, reflog_expiry_cleanup_fn cleanup_fn, void *policy_cb_data); -int reflog_expire(const char *refname, const unsigned char *sha1, +int reflog_expire(const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, diff --git a/refs/files-backend.c b/refs/files-backend.c index 014dabb0bf..2bd54e11ae 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -189,7 +189,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store, if (!refs_resolve_ref_unsafe(&refs->base, refname.buf, RESOLVE_REF_READING, - oid.hash, &flag)) { + &oid, &flag)) { oidclr(&oid); flag |= REF_ISBROKEN; } else if (is_null_oid(&oid)) { @@ -261,7 +261,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs) } static int files_read_raw_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1, + const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type) { struct files_ref_store *refs = @@ -270,6 +270,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, struct strbuf sb_path = STRBUF_INIT; const char *path; const char *buf; + const char *p; struct stat st; int fd; int ret = -1; @@ -304,7 +305,7 @@ stat_ref: if (errno != ENOENT) goto out; if (refs_read_raw_ref(refs->packed_ref_store, refname, - sha1, referent, type)) { + oid, referent, type)) { errno = ENOENT; goto out; } @@ -344,7 +345,7 @@ stat_ref: * packed ref: */ if (refs_read_raw_ref(refs->packed_ref_store, refname, - sha1, referent, type)) { + oid, referent, type)) { errno = EISDIR; goto out; } @@ -390,8 +391,8 @@ stat_ref: * Please note that FETCH_HEAD has additional * data after the sha. */ - if (get_sha1_hex(buf, sha1) || - (buf[40] != '\0' && !isspace(buf[40]))) { + if (parse_oid_hex(buf, oid, &p) || + (*p != '\0' && !isspace(*p))) { *type |= REF_ISBROKEN; errno = EINVAL; goto out; @@ -545,7 +546,7 @@ retry: */ if (files_read_raw_ref(&refs->base, refname, - lock->old_oid.hash, referent, type)) { + &lock->old_oid, referent, type)) { if (errno == ENOENT) { if (mustexist) { /* Garden variety missing reference. */ @@ -769,21 +770,21 @@ static struct ref_iterator *files_ref_iterator_begin( } /* - * Verify that the reference locked by lock has the value old_sha1. - * Fail if the reference doesn't exist and mustexist is set. Return 0 - * on success. On error, write an error message to err, set errno, and - * return a negative value. + * Verify that the reference locked by lock has the value old_oid + * (unless it is NULL). Fail if the reference doesn't exist and + * mustexist is set. Return 0 on success. On error, write an error + * message to err, set errno, and return a negative value. */ static int verify_lock(struct ref_store *ref_store, struct ref_lock *lock, - const unsigned char *old_sha1, int mustexist, + const struct object_id *old_oid, int mustexist, struct strbuf *err) { assert(err); if (refs_read_ref_full(ref_store, lock->ref_name, mustexist ? RESOLVE_REF_READING : 0, - lock->old_oid.hash, NULL)) { - if (old_sha1) { + &lock->old_oid, NULL)) { + if (old_oid) { int save_errno = errno; strbuf_addf(err, "can't verify ref '%s'", lock->ref_name); errno = save_errno; @@ -793,11 +794,11 @@ static int verify_lock(struct ref_store *ref_store, struct ref_lock *lock, return 0; } } - if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) { + if (old_oid && oidcmp(&lock->old_oid, old_oid)) { strbuf_addf(err, "ref '%s' is at %s but expected %s", lock->ref_name, oid_to_hex(&lock->old_oid), - sha1_to_hex(old_sha1)); + oid_to_hex(old_oid)); errno = EBUSY; return -1; } @@ -827,22 +828,22 @@ static int create_reflock(const char *path, void *cb) * Locks a ref returning the lock on success and NULL on failure. * On failure errno is set to something meaningful. */ -static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, - const char *refname, - const unsigned char *old_sha1, - const struct string_list *extras, - const struct string_list *skip, - unsigned int flags, int *type, - struct strbuf *err) +static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, + const char *refname, + const struct object_id *old_oid, + const struct string_list *extras, + const struct string_list *skip, + unsigned int flags, int *type, + struct strbuf *err) { struct strbuf ref_file = STRBUF_INIT; struct ref_lock *lock; int last_errno = 0; - int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); + int mustexist = (old_oid && !is_null_oid(old_oid)); int resolve_flags = RESOLVE_REF_NO_RECURSE; int resolved; - files_assert_main_repository(refs, "lock_ref_sha1_basic"); + files_assert_main_repository(refs, "lock_ref_oid_basic"); assert(err); lock = xcalloc(1, sizeof(struct ref_lock)); @@ -855,7 +856,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, files_ref_path(refs, &ref_file, refname); resolved = !!refs_resolve_ref_unsafe(&refs->base, refname, resolve_flags, - lock->old_oid.hash, type); + &lock->old_oid, type); if (!resolved && errno == EISDIR) { /* * we are trying to lock foo but we used to @@ -874,7 +875,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, } resolved = !!refs_resolve_ref_unsafe(&refs->base, refname, resolve_flags, - lock->old_oid.hash, type); + &lock->old_oid, type); } if (!resolved) { last_errno = errno; @@ -908,7 +909,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, goto error_return; } - if (verify_lock(&refs->base, lock, old_sha1, mustexist, err)) { + if (verify_lock(&refs->base, lock, old_oid, mustexist, err)) { last_errno = errno; goto error_return; } @@ -926,7 +927,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, struct ref_to_prune { struct ref_to_prune *next; - unsigned char sha1[20]; + struct object_id oid; char name[FLEX_ARRAY]; }; @@ -994,7 +995,7 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r) transaction = ref_store_transaction_begin(&refs->base, &err); if (!transaction || - ref_transaction_delete(transaction, r->name, r->sha1, + ref_transaction_delete(transaction, r->name, &r->oid, REF_ISPRUNING | REF_NODEREF, NULL, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@ -1079,7 +1080,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags) * packed-refs transaction: */ if (ref_transaction_update(transaction, iter->refname, - iter->oid->hash, NULL, + iter->oid, NULL, REF_NODEREF, NULL, &err)) die("failure preparing to create packed reference %s: %s", iter->refname, err.buf); @@ -1088,7 +1089,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags) if ((flags & PACK_REFS_PRUNE)) { struct ref_to_prune *n; FLEX_ALLOC_STR(n, name, iter->refname); - hashcpy(n->sha1, iter->oid->hash); + oidcpy(&n->oid, iter->oid); n->next = refs_to_prune; refs_to_prune = n; } @@ -1251,7 +1252,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, if (!refs_resolve_ref_unsafe(&refs->base, oldrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - orig_oid.hash, &flag)) { + &orig_oid, &flag)) { ret = error("refname %s not found", oldrefname); goto out; } @@ -1283,7 +1284,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, } if (!copy && refs_delete_ref(&refs->base, logmsg, oldrefname, - orig_oid.hash, REF_NODEREF)) { + &orig_oid, REF_NODEREF)) { error("unable to delete old %s", oldrefname); goto rollback; } @@ -1297,7 +1298,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, */ if (!copy && !refs_read_ref_full(&refs->base, newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - oid.hash, NULL) && + &oid, NULL) && refs_delete_ref(&refs->base, NULL, newrefname, NULL, REF_NODEREF)) { if (errno == EISDIR) { @@ -1323,8 +1324,8 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, logmoved = log; - lock = lock_ref_sha1_basic(refs, newrefname, NULL, NULL, NULL, - REF_NODEREF, NULL, &err); + lock = lock_ref_oid_basic(refs, newrefname, NULL, NULL, NULL, + REF_NODEREF, NULL, &err); if (!lock) { if (copy) error("unable to copy '%s' to '%s': %s", oldrefname, newrefname, err.buf); @@ -1346,8 +1347,8 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, goto out; rollback: - lock = lock_ref_sha1_basic(refs, oldrefname, NULL, NULL, NULL, - REF_NODEREF, NULL, &err); + lock = lock_ref_oid_basic(refs, oldrefname, NULL, NULL, NULL, + REF_NODEREF, NULL, &err); if (!lock) { error("unable to lock %s for rollback: %s", oldrefname, err.buf); strbuf_release(&err); @@ -1721,7 +1722,7 @@ static void update_symref_reflog(struct files_ref_store *refs, struct object_id new_oid; if (logmsg && !refs_read_ref_full(&refs->base, target, - RESOLVE_REF_READING, new_oid.hash, NULL) && + RESOLVE_REF_READING, &new_oid, NULL) && files_log_ref_write(refs, refname, &lock->old_oid, &new_oid, logmsg, 0, &err)) { error("%s", err.buf); @@ -1762,9 +1763,9 @@ static int files_create_symref(struct ref_store *ref_store, struct ref_lock *lock; int ret; - lock = lock_ref_sha1_basic(refs, refname, NULL, - NULL, NULL, REF_NODEREF, NULL, - &err); + lock = lock_ref_oid_basic(refs, refname, NULL, + NULL, NULL, REF_NODEREF, NULL, + &err); if (!lock) { error("%s", err.buf); strbuf_release(&err); @@ -2010,7 +2011,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator) if (refs_read_ref_full(iter->ref_store, diter->relative_path, 0, - iter->oid.hash, &flags)) { + &iter->oid, &flags)) { error("bad ref for %s", diter->path.buf); continue; } @@ -2148,7 +2149,7 @@ static int split_head_update(struct ref_update *update, new_update = ref_transaction_add_update( transaction, "HEAD", update->flags | REF_LOG_ONLY | REF_NODEREF, - update->new_oid.hash, update->old_oid.hash, + &update->new_oid, &update->old_oid, update->msg); /* @@ -2212,7 +2213,7 @@ static int split_symref_update(struct files_ref_store *refs, new_update = ref_transaction_add_update( transaction, referent, new_flags, - update->new_oid.hash, update->old_oid.hash, + &update->new_oid, &update->old_oid, update->msg); new_update->parent_update = update; @@ -2347,7 +2348,7 @@ static int lock_ref_for_update(struct files_ref_store *refs, */ if (refs_read_ref_full(&refs->base, referent.buf, 0, - lock->old_oid.hash, NULL)) { + &lock->old_oid, NULL)) { if (update->flags & REF_HAVE_OLD) { strbuf_addf(err, "cannot lock ref '%s': " "error reading reference", @@ -2570,7 +2571,7 @@ static int files_transaction_prepare(struct ref_store *ref_store, ret = lock_ref_for_update(refs, update, transaction, head_ref, &affected_refnames, err); if (ret) - break; + goto cleanup; if (update->flags & REF_DELETING && !(update->flags & REF_LOG_ONLY) && @@ -2594,7 +2595,7 @@ static int files_transaction_prepare(struct ref_store *ref_store, ref_transaction_add_update( packed_transaction, update->refname, update->flags & ~REF_HAVE_OLD, - update->new_oid.hash, update->old_oid.hash, + &update->new_oid, &update->old_oid, NULL); } } @@ -2847,7 +2848,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store, */ ref_transaction_add_update(packed_transaction, update->refname, update->flags & ~REF_HAVE_OLD, - update->new_oid.hash, update->old_oid.hash, + &update->new_oid, &update->old_oid, NULL); } @@ -2908,7 +2909,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, } static int files_reflog_expire(struct ref_store *ref_store, - const char *refname, const unsigned char *sha1, + const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, @@ -2925,7 +2926,6 @@ static int files_reflog_expire(struct ref_store *ref_store, int status = 0; int type; struct strbuf err = STRBUF_INIT; - struct object_id oid; memset(&cb, 0, sizeof(cb)); cb.flags = flags; @@ -2937,9 +2937,9 @@ static int files_reflog_expire(struct ref_store *ref_store, * reference itself, plus we might need to update the * reference if --updateref was specified: */ - lock = lock_ref_sha1_basic(refs, refname, sha1, - NULL, NULL, REF_NODEREF, - &type, &err); + lock = lock_ref_oid_basic(refs, refname, oid, + NULL, NULL, REF_NODEREF, + &type, &err); if (!lock) { error("cannot lock ref '%s': %s", refname, err.buf); strbuf_release(&err); @@ -2975,9 +2975,7 @@ static int files_reflog_expire(struct ref_store *ref_store, } } - hashcpy(oid.hash, sha1); - - (*prepare_fn)(refname, &oid, cb.policy_cb); + (*prepare_fn)(refname, oid, cb.policy_cb); refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb); (*cleanup_fn)(cb.policy_cb); diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 3279d42c5a..74f1dea0f4 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -716,7 +716,7 @@ static struct snapshot *get_snapshot(struct packed_ref_store *refs) } static int packed_read_raw_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1, + const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type) { struct packed_ref_store *refs = @@ -734,7 +734,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, return -1; } - if (get_sha1_hex(rec, sha1)) + if (get_oid_hex(rec, oid)) die_invalid_line(refs->path, rec, snapshot->eof - rec); *type = REF_ISPACKED; @@ -880,7 +880,7 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator, } else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) { return -1; } else { - return !!peel_object(iter->oid.hash, peeled->hash); + return !!peel_object(&iter->oid, peeled); } } @@ -1220,8 +1220,8 @@ static int write_with_updates(struct packed_ref_store *refs, i++; } else { struct object_id peeled; - int peel_error = peel_object(update->new_oid.hash, - peeled.hash); + int peel_error = peel_object(&update->new_oid, + &peeled); if (write_packed_entry(out, update->refname, update->new_oid.hash, @@ -1519,7 +1519,7 @@ static int packed_delete_reflog(struct ref_store *ref_store, } static int packed_reflog_expire(struct ref_store *ref_store, - const char *refname, const unsigned char *sha1, + const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, diff --git a/refs/ref-cache.c b/refs/ref-cache.c index 4f850e1b5c..043eb83748 100644 --- a/refs/ref-cache.c +++ b/refs/ref-cache.c @@ -493,7 +493,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator) static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator, struct object_id *peeled) { - return peel_object(ref_iterator->oid->hash, peeled->hash); + return peel_object(ref_iterator->oid, peeled); } static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator) diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 448de4bccb..b0f3e300c7 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -120,11 +120,11 @@ enum peel_status { /* * Peel the named object; i.e., if the object is a tag, resolve the * tag recursively until a non-tag is found. If successful, store the - * result to sha1 and return PEEL_PEELED. If the object is not a tag + * result to oid and return PEEL_PEELED. If the object is not a tag * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively, * and leave sha1 unchanged. */ -enum peel_status peel_object(const unsigned char *name, unsigned char *sha1); +enum peel_status peel_object(const struct object_id *name, struct object_id *oid); /* * Copy the reflog message msg to buf, which has been allocated sufficiently @@ -181,7 +181,7 @@ struct ref_update { }; int refs_read_raw_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1, + const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type); /* @@ -202,8 +202,8 @@ int ref_update_reject_duplicates(struct string_list *refnames, struct ref_update *ref_transaction_add_update( struct ref_transaction *transaction, const char *refname, unsigned int flags, - const unsigned char *new_sha1, - const unsigned char *old_sha1, + const struct object_id *new_oid, + const struct object_id *old_oid, const char *msg); /* @@ -608,7 +608,7 @@ typedef int create_reflog_fn(struct ref_store *ref_store, const char *refname, int force_create, struct strbuf *err); typedef int delete_reflog_fn(struct ref_store *ref_store, const char *refname); typedef int reflog_expire_fn(struct ref_store *ref_store, - const char *refname, const unsigned char *sha1, + const char *refname, const struct object_id *oid, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, @@ -619,13 +619,13 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * Read a reference from the specified reference store, non-recursively. * Set type to describe the reference, and: * - * - If refname is the name of a normal reference, fill in sha1 + * - If refname is the name of a normal reference, fill in oid * (leaving referent unchanged). * * - If refname is the name of a symbolic reference, write the full * name of the reference to which it refers (e.g. * "refs/heads/master") to referent and set the REF_ISSYMREF bit in - * type (leaving sha1 unchanged). The caller is responsible for + * type (leaving oid unchanged). The caller is responsible for * validating that referent is a valid reference name. * * WARNING: refname might be used as part of a filename, so it is @@ -637,7 +637,7 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * * Return 0 on success. If the ref doesn't exist, set errno to ENOENT * and return -1. If the ref exists but is neither a symbolic ref nor - * a sha1, it is broken; set REF_ISBROKEN in type, set errno to + * an object ID, it is broken; set REF_ISBROKEN in type, set errno to * EINVAL, and return -1. If there is another error reading the ref, * set errno appropriately and return -1. * @@ -654,7 +654,7 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * refname will still be valid and unchanged. */ typedef int read_raw_ref_fn(struct ref_store *ref_store, - const char *refname, unsigned char *sha1, + const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type); struct ref_storage_be { diff --git a/remote-testsvn.c b/remote-testsvn.c index 0ff4a31262..bcebb4c789 100644 --- a/remote-testsvn.c +++ b/remote-testsvn.c @@ -174,7 +174,7 @@ static int cmd_import(const char *line) struct child_process svndump_proc = CHILD_PROCESS_INIT; const char *command = "svnrdump"; - if (read_ref(private_ref, head_oid.hash)) + if (read_ref(private_ref, &head_oid)) startrev = 0; else { note_msg = read_ref_note(&head_oid); @@ -1629,7 +1629,7 @@ static void set_merge(struct branch *ret) strcmp(ret->remote_name, ".")) continue; if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]), - oid.hash, &ref) == 1) + &oid, &ref) == 1) ret->merge[i]->dst = ref; else ret->merge[i]->dst = xstrdup(ret->merge_name[i]); @@ -2002,13 +2002,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, return -1; /* Cannot stat if what we used to build on no longer exists */ - if (read_ref(base, oid.hash)) + if (read_ref(base, &oid)) return -1; theirs = lookup_commit_reference(&oid); if (!theirs) return -1; - if (read_ref(branch->refname, oid.hash)) + if (read_ref(branch->refname, &oid)) return -1; ours = lookup_commit_reference(&oid); if (!ours) @@ -2327,7 +2327,7 @@ static int remote_tracking(struct remote *remote, const char *refname, dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); if (!dst) return -1; /* no tracking ref for refname at remote */ - if (read_ref(dst, oid->hash)) + if (read_ref(dst, oid)) return -1; /* we know what the tracking ref is but we cannot read it */ return 0; } diff --git a/revision.c b/revision.c index d167223e69..99c95c19b0 100644 --- a/revision.c +++ b/revision.c @@ -395,8 +395,16 @@ static struct commit *one_relevant_parent(const struct rev_info *revs, * if the whole diff is removal of old data, and otherwise * REV_TREE_DIFFERENT (of course if the trees are the same we * want REV_TREE_SAME). - * That means that once we get to REV_TREE_DIFFERENT, we do not - * have to look any further. + * + * The only time we care about the distinction is when + * remove_empty_trees is in effect, in which case we care only about + * whether the whole change is REV_TREE_NEW, or if there's another type + * of change. Which means we can stop the diff early in either of these + * cases: + * + * 1. We're not using remove_empty_trees at all. + * + * 2. We saw anything except REV_TREE_NEW. */ static int tree_difference = REV_TREE_SAME; @@ -407,9 +415,10 @@ static void file_add_remove(struct diff_options *options, const char *fullpath, unsigned dirty_submodule) { int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; + struct rev_info *revs = options->change_fn_data; tree_difference |= diff; - if (tree_difference == REV_TREE_DIFFERENT) + if (!revs->remove_empty_trees || tree_difference != REV_TREE_NEW) DIFF_OPT_SET(options, HAS_CHANGES); } @@ -1407,6 +1416,7 @@ void init_revisions(struct rev_info *revs, const char *prefix) DIFF_OPT_SET(&revs->pruning, QUICK); revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; + revs->pruning.change_fn_data = revs; revs->sort_order = REV_SORT_IN_GRAPH_ORDER; revs->dense = 1; revs->prefix = prefix; diff --git a/run-command.c b/run-command.c index 014b2165b5..31fc5ea86e 100644 --- a/run-command.c +++ b/run-command.c @@ -5,6 +5,7 @@ #include "argv-array.h" #include "thread-utils.h" #include "strbuf.h" +#include "string-list.h" void child_process_init(struct child_process *child) { @@ -1169,11 +1170,28 @@ const char *find_hook(const char *name) strbuf_reset(&path); strbuf_git_path(&path, "hooks/%s", name); if (access(path.buf, X_OK) < 0) { + int err = errno; + #ifdef STRIP_EXTENSION strbuf_addstr(&path, STRIP_EXTENSION); if (access(path.buf, X_OK) >= 0) return path.buf; + if (errno == EACCES) + err = errno; #endif + + if (err == EACCES && advice_ignored_hook) { + static struct string_list advise_given = STRING_LIST_INIT_DUP; + + if (!string_list_lookup(&advise_given, name)) { + string_list_insert(&advise_given, name); + advise(_("The '%s' hook was ignored because " + "it's not set as executable.\n" + "You can disable this warning with " + "`git config advice.ignoredHook false`."), + path.buf); + } + } return NULL; } return path.buf; diff --git a/sequencer.c b/sequencer.c index f2a10cc4f2..1eb2c4669d 100644 --- a/sequencer.c +++ b/sequencer.c @@ -393,7 +393,7 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, "HEAD", - to->hash, unborn ? null_sha1 : from->hash, + to, unborn ? &null_oid : from, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@ -489,7 +489,7 @@ static int is_index_unchanged(void) struct object_id head_oid; struct commit *head_commit; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return error(_("could not resolve HEAD commit\n")); head_commit = lookup_commit(&head_oid); @@ -1115,11 +1115,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, * write it at all. */ if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) && - update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.oid.hash, NULL, + update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL, REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) res = -1; if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) && - update_ref(NULL, "REVERT_HEAD", commit->object.oid.hash, NULL, + update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL, REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) res = -1; @@ -1184,7 +1184,6 @@ static int read_and_refresh_cache(struct replay_opts *opts) refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); if (the_index.cache_changed && index_fd >= 0) { if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) { - rollback_lock_file(&index_lock); return error(_("git %s: failed to refresh the index"), _(action_name(opts))); } @@ -1630,7 +1629,7 @@ static int rollback_single_pick(void) if (!file_exists(git_path_cherry_pick_head()) && !file_exists(git_path_revert_head())) return error(_("no cherry-pick or revert in progress")); - if (read_ref_full("HEAD", 0, head_oid.hash, NULL)) + if (read_ref_full("HEAD", 0, &head_oid, NULL)) return error(_("cannot resolve HEAD")); if (is_null_oid(&head_oid)) return error(_("cannot abort from a branch yet to be born")); @@ -1862,12 +1861,15 @@ static int error_failed_squash(struct commit *commit, static int do_exec(const char *command_line) { + struct argv_array child_env = ARGV_ARRAY_INIT; const char *child_argv[] = { NULL, NULL }; int dirty, status; fprintf(stderr, "Executing: %s\n", command_line); child_argv[0] = command_line; - status = run_command_v_opt(child_argv, RUN_USING_SHELL); + argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + status = run_command_v_opt_cd_env(child_argv, RUN_USING_SHELL, NULL, + child_env.argv); /* force re-reading of the cache */ if (discard_cache() < 0 || read_cache() < 0) @@ -1897,6 +1899,8 @@ static int do_exec(const char *command_line) status = 1; } + argv_array_clear(&child_env); + return status; } @@ -2124,8 +2128,8 @@ cleanup_head_ref: } msg = reflog_message(opts, "finish", "%s onto %s", head_ref.buf, buf.buf); - if (update_ref(msg, head_ref.buf, head.hash, orig.hash, - REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) { + if (update_ref(msg, head_ref.buf, &head, &orig, + REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) { res = error(_("could not update %s"), head_ref.buf); goto cleanup_head_ref; diff --git a/sha1_file.c b/sha1_file.c index 10c3a0083d..d7de8184ed 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -456,19 +456,19 @@ struct alternate_object_database *alloc_alt_odb(const char *dir) void add_to_alternates_file(const char *reference) { - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + struct lock_file lock = LOCK_INIT; char *alts = git_pathdup("objects/info/alternates"); FILE *in, *out; + int found = 0; - hold_lock_file_for_update(lock, alts, LOCK_DIE_ON_ERROR); - out = fdopen_lock_file(lock, "w"); + hold_lock_file_for_update(&lock, alts, LOCK_DIE_ON_ERROR); + out = fdopen_lock_file(&lock, "w"); if (!out) die_errno("unable to fdopen alternates lockfile"); in = fopen(alts, "r"); if (in) { struct strbuf line = STRBUF_INIT; - int found = 0; while (strbuf_getline(&line, in) != EOF) { if (!strcmp(reference, line.buf)) { @@ -480,18 +480,15 @@ void add_to_alternates_file(const char *reference) strbuf_release(&line); fclose(in); - - if (found) { - rollback_lock_file(lock); - lock = NULL; - } } else if (errno != ENOENT) die_errno("unable to read alternates file"); - if (lock) { + if (found) { + rollback_lock_file(&lock); + } else { fprintf_or_die(out, "%s\n", reference); - if (commit_lock_file(lock)) + if (commit_lock_file(&lock)) die_errno("unable to move new alternates file into place"); if (alt_odb_tail) link_alt_odb_entries(reference, '\n', NULL, 0); @@ -1664,7 +1661,7 @@ static void check_tag(const void *buf, size_t size) die("corrupt tag"); } -static int index_mem(unsigned char *sha1, void *buf, size_t size, +static int index_mem(struct object_id *oid, void *buf, size_t size, enum object_type type, const char *path, unsigned flags) { @@ -1695,15 +1692,15 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, } if (write_object) - ret = write_sha1_file(buf, size, typename(type), sha1); + ret = write_sha1_file(buf, size, typename(type), oid->hash); else - ret = hash_sha1_file(buf, size, typename(type), sha1); + ret = hash_sha1_file(buf, size, typename(type), oid->hash); if (re_allocated) free(buf); return ret; } -static int index_stream_convert_blob(unsigned char *sha1, int fd, +static int index_stream_convert_blob(struct object_id *oid, int fd, const char *path, unsigned flags) { int ret; @@ -1718,22 +1715,22 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd, if (write_object) ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB), - sha1); + oid->hash); else ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB), - sha1); + oid->hash); strbuf_release(&sbuf); return ret; } -static int index_pipe(unsigned char *sha1, int fd, enum object_type type, +static int index_pipe(struct object_id *oid, int fd, enum object_type type, const char *path, unsigned flags) { struct strbuf sbuf = STRBUF_INIT; int ret; if (strbuf_read(&sbuf, fd, 4096) >= 0) - ret = index_mem(sha1, sbuf.buf, sbuf.len, type, path, flags); + ret = index_mem(oid, sbuf.buf, sbuf.len, type, path, flags); else ret = -1; strbuf_release(&sbuf); @@ -1742,14 +1739,14 @@ static int index_pipe(unsigned char *sha1, int fd, enum object_type type, #define SMALL_FILE_SIZE (32*1024) -static int index_core(unsigned char *sha1, int fd, size_t size, +static int index_core(struct object_id *oid, int fd, size_t size, enum object_type type, const char *path, unsigned flags) { int ret; if (!size) { - ret = index_mem(sha1, "", size, type, path, flags); + ret = index_mem(oid, "", size, type, path, flags); } else if (size <= SMALL_FILE_SIZE) { char *buf = xmalloc(size); ssize_t read_result = read_in_full(fd, buf, size); @@ -1760,11 +1757,11 @@ static int index_core(unsigned char *sha1, int fd, size_t size, ret = error("short read while indexing %s", path ? path : "<unknown>"); else - ret = index_mem(sha1, buf, size, type, path, flags); + ret = index_mem(oid, buf, size, type, path, flags); free(buf); } else { void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - ret = index_mem(sha1, buf, size, type, path, flags); + ret = index_mem(oid, buf, size, type, path, flags); munmap(buf, size); } return ret; @@ -1802,12 +1799,12 @@ int index_fd(struct object_id *oid, int fd, struct stat *st, * die() for large files. */ if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(path)) - ret = index_stream_convert_blob(oid->hash, fd, path, flags); + ret = index_stream_convert_blob(oid, fd, path, flags); else if (!S_ISREG(st->st_mode)) - ret = index_pipe(oid->hash, fd, type, path, flags); + ret = index_pipe(oid, fd, type, path, flags); else if (st->st_size <= big_file_threshold || type != OBJ_BLOB || (path && would_convert_to_git(&the_index, path))) - ret = index_core(oid->hash, fd, xsize_t(st->st_size), type, path, + ret = index_core(oid, fd, xsize_t(st->st_size), type, path, flags); else ret = index_stream(oid, fd, xsize_t(st->st_size), type, path, @@ -1841,7 +1838,7 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne strbuf_release(&sb); break; case S_IFDIR: - return resolve_gitlink_ref(path, "HEAD", oid->hash); + return resolve_gitlink_ref(path, "HEAD", oid); default: return error("%s: unsupported file type", path); } diff --git a/sha1_name.c b/sha1_name.c index c7c5ab376c..9a2d5caf3b 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -153,7 +153,9 @@ static void unique_in_pack(struct packed_git *p, uint32_t num, last, i, first = 0; const struct object_id *current = NULL; - open_pack_index(p); + if (open_pack_index(p) || !p->num_objects) + return; + num = p->num_objects; last = num; while (first < last) { @@ -474,10 +476,104 @@ static unsigned msb(unsigned long val) return r; } -int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len) +struct min_abbrev_data { + unsigned int init_len; + unsigned int cur_len; + char *hex; + const unsigned char *hash; +}; + +static inline char get_hex_char_from_oid(const struct object_id *oid, + unsigned int pos) +{ + static const char hex[] = "0123456789abcdef"; + + if ((pos & 1) == 0) + return hex[oid->hash[pos >> 1] >> 4]; + else + return hex[oid->hash[pos >> 1] & 0xf]; +} + +static int extend_abbrev_len(const struct object_id *oid, void *cb_data) +{ + struct min_abbrev_data *mad = cb_data; + + unsigned int i = mad->init_len; + while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i)) + i++; + + if (i < GIT_MAX_RAWSZ && i >= mad->cur_len) + mad->cur_len = i + 1; + + return 0; +} + +static void find_abbrev_len_for_pack(struct packed_git *p, + struct min_abbrev_data *mad) +{ + int match = 0; + uint32_t num, last, first = 0; + struct object_id oid; + + if (open_pack_index(p) || !p->num_objects) + return; + + num = p->num_objects; + last = num; + while (first < last) { + uint32_t mid = first + (last - first) / 2; + const unsigned char *current; + int cmp; + + current = nth_packed_object_sha1(p, mid); + cmp = hashcmp(mad->hash, current); + if (!cmp) { + match = 1; + first = mid; + break; + } + if (cmp > 0) { + first = mid + 1; + continue; + } + last = mid; + } + + /* + * first is now the position in the packfile where we would insert + * mad->hash if it does not exist (or the position of mad->hash if + * it does exist). Hence, we consider a maximum of three objects + * nearby for the abbreviation length. + */ + mad->init_len = 0; + if (!match) { + nth_packed_object_oid(&oid, p, first); + extend_abbrev_len(&oid, mad); + } else if (first < num - 1) { + nth_packed_object_oid(&oid, p, first + 1); + extend_abbrev_len(&oid, mad); + } + if (first > 0) { + nth_packed_object_oid(&oid, p, first - 1); + extend_abbrev_len(&oid, mad); + } + mad->init_len = mad->cur_len; +} + +static void find_abbrev_len_packed(struct min_abbrev_data *mad) { - int status, exists; + struct packed_git *p; + + prepare_packed_git(); + for (p = packed_git; p; p = p->next) + find_abbrev_len_for_pack(p, mad); +} +int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len) +{ + struct disambiguate_state ds; + struct min_abbrev_data mad; + struct object_id oid_ret; if (len < 0) { unsigned long count = approximate_object_count(); /* @@ -503,19 +599,26 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len) sha1_to_hex_r(hex, sha1); if (len == GIT_SHA1_HEXSZ || !len) return GIT_SHA1_HEXSZ; - exists = has_sha1_file(sha1); - while (len < GIT_SHA1_HEXSZ) { - struct object_id oid_ret; - status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY); - if (exists - ? !status - : status == SHORT_NAME_NOT_FOUND) { - hex[len] = 0; - return len; - } - len++; - } - return len; + + mad.init_len = len; + mad.cur_len = len; + mad.hex = hex; + mad.hash = sha1; + + find_abbrev_len_packed(&mad); + + if (init_object_disambiguation(hex, mad.cur_len, &ds) < 0) + return -1; + + ds.fn = extend_abbrev_len; + ds.always_call_fn = 1; + ds.cb_data = (void *)&mad; + + find_short_object_filename(&ds); + (void)finish_object_disambiguation(&ds, &oid_ret); + + hex[mad.cur_len] = 0; + return mad.cur_len; } const char *find_unique_abbrev(const unsigned char *sha1, int len) @@ -603,7 +706,7 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid, if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) { if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) { - refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref); + refs_found = dwim_ref(str, len, &tmp_oid, &real_ref); if (refs_found > 0) { warning(warn_msg, len, str); if (advice_object_name_warning) @@ -654,11 +757,11 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid, if (!len && reflog_len) /* allow "@{...}" to mean the current branch reflog */ - refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref); + refs_found = dwim_ref("HEAD", 4, oid, &real_ref); else if (reflog_len) - refs_found = dwim_log(str, len, oid->hash, &real_ref); + refs_found = dwim_log(str, len, oid, &real_ref); else - refs_found = dwim_ref(str, len, oid->hash, &real_ref); + refs_found = dwim_ref(str, len, oid, &real_ref); if (!refs_found) return -1; @@ -697,7 +800,7 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid, return -1; } } - if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL, + if (read_ref_at(real_ref, flags, at_time, nth, oid, NULL, &co_time, &co_tz, &co_cnt)) { if (!len) { if (starts_with(real_ref, "refs/heads/")) { @@ -1331,7 +1434,10 @@ void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed) int strbuf_check_branch_ref(struct strbuf *sb, const char *name) { - strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL); + if (startup_info->have_repository) + strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL); + else + strbuf_addstr(sb, name); if (name[0] == '-') return -1; strbuf_splice(sb, 0, 0, "refs/heads/", 11); diff --git a/submodule-config.h b/submodule-config.h index e3845831f6..a5503a5d17 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -22,6 +22,9 @@ struct submodule { int recommend_shallow; }; +#define SUBMODULE_INIT { NULL, NULL, NULL, RECURSE_SUBMODULES_NONE, \ + NULL, NULL, SUBMODULE_UPDATE_STRATEGY_INIT, {0}, -1 }; + struct submodule_cache; struct repository; diff --git a/submodule.c b/submodule.c index 63e7094e16..239d94d539 100644 --- a/submodule.c +++ b/submodule.c @@ -21,7 +21,7 @@ #include "parse-options.h" static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF; -static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP; +static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP; static int initialized_fetch_ref_tips; static struct oid_array ref_tips_before_fetch; static struct oid_array ref_tips_after_fetch; @@ -674,11 +674,11 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce) } static struct oid_array *submodule_commits(struct string_list *submodules, - const char *path) + const char *name) { struct string_list_item *item; - item = string_list_insert(submodules, path); + item = string_list_insert(submodules, name); if (item->util) return (struct oid_array *) item->util; @@ -687,39 +687,67 @@ static struct oid_array *submodule_commits(struct string_list *submodules, return (struct oid_array *) item->util; } +struct collect_changed_submodules_cb_data { + struct string_list *changed; + const struct object_id *commit_oid; +}; + +/* + * this would normally be two functions: default_name_from_path() and + * path_from_default_name(). Since the default name is the same as + * the submodule path we can get away with just one function which only + * checks whether there is a submodule in the working directory at that + * location. + */ +static const char *default_name_or_path(const char *path_or_name) +{ + int error_code; + + if (!is_submodule_populated_gently(path_or_name, &error_code)) + return NULL; + + return path_or_name; +} + static void collect_changed_submodules_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) { + struct collect_changed_submodules_cb_data *me = data; + struct string_list *changed = me->changed; + const struct object_id *commit_oid = me->commit_oid; int i; - struct string_list *changed = data; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; struct oid_array *commits; + const struct submodule *submodule; + const char *name; + if (!S_ISGITLINK(p->two->mode)) continue; - if (S_ISGITLINK(p->one->mode)) { - /* - * NEEDSWORK: We should honor the name configured in - * the .gitmodules file of the commit we are examining - * here to be able to correctly follow submodules - * being moved around. - */ - commits = submodule_commits(changed, p->two->path); - oid_array_append(commits, &p->two->oid); - } else { - /* Submodule is new or was moved here */ - /* - * NEEDSWORK: When the .git directories of submodules - * live inside the superprojects .git directory some - * day we should fetch new submodules directly into - * that location too when config or options request - * that so they can be checked out from there. - */ - continue; + submodule = submodule_from_path(commit_oid, p->two->path); + if (submodule) + name = submodule->name; + else { + name = default_name_or_path(p->two->path); + /* make sure name does not collide with existing one */ + submodule = submodule_from_name(commit_oid, name); + if (submodule) { + warning("Submodule in commit %s at path: " + "'%s' collides with a submodule named " + "the same. Skipping it.", + oid_to_hex(commit_oid), name); + name = NULL; + } } + + if (!name) + continue; + + commits = submodule_commits(changed, name); + oid_array_append(commits, &p->two->oid); } } @@ -742,11 +770,14 @@ static void collect_changed_submodules(struct string_list *changed, while ((commit = get_revision(&rev))) { struct rev_info diff_rev; + struct collect_changed_submodules_cb_data data; + data.changed = changed; + data.commit_oid = &commit->object.oid; init_revisions(&diff_rev, NULL); diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; diff_rev.diffopt.format_callback = collect_changed_submodules_cb; - diff_rev.diffopt.format_callback_data = changed; + diff_rev.diffopt.format_callback_data = &data; diff_tree_combined_merge(commit, 1, &diff_rev); } @@ -894,7 +925,7 @@ int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) { struct string_list submodules = STRING_LIST_INIT_DUP; - struct string_list_item *submodule; + struct string_list_item *name; struct argv_array argv = ARGV_ARRAY_INIT; /* argv.argv[0] will be ignored by setup_revisions */ @@ -905,9 +936,19 @@ int find_unpushed_submodules(struct oid_array *commits, collect_changed_submodules(&submodules, &argv); - for_each_string_list_item(submodule, &submodules) { - struct oid_array *commits = submodule->util; - const char *path = submodule->string; + for_each_string_list_item(name, &submodules) { + struct oid_array *commits = name->util; + const struct submodule *submodule; + const char *path = NULL; + + submodule = submodule_from_name(&null_oid, name->string); + if (submodule) + path = submodule->path; + else + path = default_name_or_path(name->string); + + if (!path) + continue; if (submodule_needs_pushing(path, commits)) string_list_insert(needs_pushing, path); @@ -1016,7 +1057,7 @@ int push_unpushed_submodules(struct oid_array *commits, char *head; struct object_id head_oid; - head = resolve_refdup("HEAD", 0, head_oid.hash, NULL); + head = resolve_refdup("HEAD", 0, &head_oid, NULL); if (!head) die(_("Failed to resolve HEAD as a valid ref.")); @@ -1065,7 +1106,7 @@ static void calculate_changed_submodule_paths(void) { struct argv_array argv = ARGV_ARRAY_INIT; struct string_list changed_submodules = STRING_LIST_INIT_DUP; - const struct string_list_item *item; + const struct string_list_item *name; /* No need to check if there are no submodules configured */ if (!submodule_from_path(NULL, NULL)) @@ -1080,16 +1121,26 @@ static void calculate_changed_submodule_paths(void) /* * Collect all submodules (whether checked out or not) for which new - * commits have been recorded upstream in "changed_submodule_paths". + * commits have been recorded upstream in "changed_submodule_names". */ collect_changed_submodules(&changed_submodules, &argv); - for_each_string_list_item(item, &changed_submodules) { - struct oid_array *commits = item->util; - const char *path = item->string; + for_each_string_list_item(name, &changed_submodules) { + struct oid_array *commits = name->util; + const struct submodule *submodule; + const char *path = NULL; + + submodule = submodule_from_name(&null_oid, name->string); + if (submodule) + path = submodule->path; + else + path = default_name_or_path(name->string); + + if (!path) + continue; if (!submodule_has_commits(path, commits)) - string_list_append(&changed_submodule_paths, path); + string_list_append(&changed_submodule_names, name->string); } free_submodules_oids(&changed_submodules); @@ -1136,6 +1187,31 @@ struct submodule_parallel_fetch { }; #define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0} +static int get_fetch_recurse_config(const struct submodule *submodule, + struct submodule_parallel_fetch *spf) +{ + if (spf->command_line_option != RECURSE_SUBMODULES_DEFAULT) + return spf->command_line_option; + + if (submodule) { + char *key; + const char *value; + + int fetch_recurse = submodule->fetch_recurse; + key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name); + if (!repo_config_get_string_const(the_repository, key, &value)) { + fetch_recurse = parse_fetch_recurse_submodules_arg(key, value); + } + free(key); + + if (fetch_recurse != RECURSE_SUBMODULES_NONE) + /* local config overrules everything except commandline */ + return fetch_recurse; + } + + return spf->default_option; +} + static int get_next_submodule(struct child_process *cp, struct strbuf *err, void *data, void **task_cb) { @@ -1149,49 +1225,35 @@ static int get_next_submodule(struct child_process *cp, const struct cache_entry *ce = active_cache[spf->count]; const char *git_dir, *default_argv; const struct submodule *submodule; + struct submodule default_submodule = SUBMODULE_INIT; if (!S_ISGITLINK(ce->ce_mode)) continue; submodule = submodule_from_path(&null_oid, ce->name); - - default_argv = "yes"; - if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) { - int fetch_recurse = RECURSE_SUBMODULES_NONE; - - if (submodule) { - char *key; - const char *value; - - fetch_recurse = submodule->fetch_recurse; - key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name); - if (!repo_config_get_string_const(the_repository, key, &value)) { - fetch_recurse = parse_fetch_recurse_submodules_arg(key, value); - } - free(key); + if (!submodule) { + const char *name = default_name_or_path(ce->name); + if (name) { + default_submodule.path = default_submodule.name = name; + submodule = &default_submodule; } + } - if (fetch_recurse != RECURSE_SUBMODULES_NONE) { - if (fetch_recurse == RECURSE_SUBMODULES_OFF) - continue; - if (fetch_recurse == RECURSE_SUBMODULES_ON_DEMAND) { - if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) - continue; - default_argv = "on-demand"; - } - } else { - if (spf->default_option == RECURSE_SUBMODULES_OFF) - continue; - if (spf->default_option == RECURSE_SUBMODULES_ON_DEMAND) { - if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) - continue; - default_argv = "on-demand"; - } - } - } else if (spf->command_line_option == RECURSE_SUBMODULES_ON_DEMAND) { - if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) + switch (get_fetch_recurse_config(submodule, spf)) + { + default: + case RECURSE_SUBMODULES_DEFAULT: + case RECURSE_SUBMODULES_ON_DEMAND: + if (!submodule || !unsorted_string_list_lookup(&changed_submodule_names, + submodule->name)) continue; default_argv = "on-demand"; + break; + case RECURSE_SUBMODULES_ON: + default_argv = "yes"; + break; + case RECURSE_SUBMODULES_OFF: + continue; } strbuf_addf(&submodule_path, "%s/%s", spf->work_tree, ce->name); @@ -1282,7 +1344,7 @@ int fetch_populated_submodules(const struct argv_array *options, argv_array_clear(&spf.args); out: - string_list_clear(&changed_submodule_paths, 1); + string_list_clear(&changed_submodule_names, 1); return spf.result; } diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 05d8c4d8af..7120634b04 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -72,12 +72,12 @@ static int cmd_pack_refs(struct ref_store *refs, const char **argv) static int cmd_peel_ref(struct ref_store *refs, const char **argv) { const char *refname = notnull(*argv++, "refname"); - unsigned char sha1[20]; + struct object_id oid; int ret; - ret = refs_peel_ref(refs, refname, sha1); + ret = refs_peel_ref(refs, refname, &oid); if (!ret) - puts(sha1_to_hex(sha1)); + puts(oid_to_hex(&oid)); return ret; } @@ -127,15 +127,15 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv) static int cmd_resolve_ref(struct ref_store *refs, const char **argv) { - unsigned char sha1[20]; + struct object_id oid; const char *refname = notnull(*argv++, "refname"); int resolve_flags = arg_flags(*argv++, "resolve-flags"); int flags; const char *ref; ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags, - sha1, &flags); - printf("%s %s 0x%x\n", sha1_to_hex(sha1), ref, flags); + &oid, &flags); + printf("%s %s 0x%x\n", oid_to_hex(&oid), ref ? ref : "(null)", flags); return ref ? 0 : 1; } @@ -218,12 +218,12 @@ static int cmd_delete_ref(struct ref_store *refs, const char **argv) const char *refname = notnull(*argv++, "refname"); const char *sha1_buf = notnull(*argv++, "old-sha1"); unsigned int flags = arg_flags(*argv++, "flags"); - unsigned char old_sha1[20]; + struct object_id old_oid; - if (get_sha1_hex(sha1_buf, old_sha1)) + if (get_oid_hex(sha1_buf, &old_oid)) die("not sha-1"); - return refs_delete_ref(refs, msg, refname, old_sha1, flags); + return refs_delete_ref(refs, msg, refname, &old_oid, flags); } static int cmd_update_ref(struct ref_store *refs, const char **argv) @@ -233,15 +233,15 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv) const char *new_sha1_buf = notnull(*argv++, "old-sha1"); const char *old_sha1_buf = notnull(*argv++, "old-sha1"); unsigned int flags = arg_flags(*argv++, "flags"); - unsigned char old_sha1[20]; - unsigned char new_sha1[20]; + struct object_id old_oid; + struct object_id new_oid; - if (get_sha1_hex(old_sha1_buf, old_sha1) || - get_sha1_hex(new_sha1_buf, new_sha1)) + if (get_oid_hex(old_sha1_buf, &old_oid) || + get_oid_hex(new_sha1_buf, &new_oid)) die("not sha-1"); return refs_update_ref(refs, msg, refname, - new_sha1, old_sha1, + &new_oid, &old_oid, flags, UPDATE_REFS_DIE_ON_ERR); } diff --git a/t/perf/p4211-line-log.sh b/t/perf/p4211-line-log.sh index b7ff68d4fa..e0ed05907c 100755 --- a/t/perf/p4211-line-log.sh +++ b/t/perf/p4211-line-log.sh @@ -31,4 +31,8 @@ test_perf 'git log -L (renames on)' ' git log -M -L 1:"$file" >/dev/null ' +test_perf 'git log --oneline --raw --parents' ' + git log --oneline --raw --parents >/dev/null +' + test_done diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 1aa5093f36..7fd87dd544 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -20,6 +20,31 @@ modification *should* take notice and update the test vectors here. . ./test-lib.sh +try_local_x () { + local x="local" && + echo "$x" +} + +# This test is an experiment to check whether any Git users are using +# Shells that don't support the "local" keyword. "local" is not +# POSIX-standard, but it is very widely supported by POSIX-compliant +# shells, and if it doesn't cause problems for people, we would like +# to be able to use it in Git code. +# +# For now, this is the only test that requires "local". If your shell +# fails this test, you can ignore the failure, but please report the +# problem to the Git mailing list <git@vger.kernel.org>, as it might +# convince us to continue avoiding the use of "local". +test_expect_success 'verify that the running shell supports "local"' ' + x="notlocal" && + echo "local" >expected1 && + try_local_x >actual1 && + test_cmp expected1 actual1 && + echo "notlocal" >expected2 && + echo "$x" >actual2 && + test_cmp expected2 actual2 +' + ################################################################ # git init has been done in an empty repository. # make sure it is empty. diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index deb3ae7813..68108d956a 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -315,7 +315,7 @@ test_expect_success 'setup master' ' echo >.gitattributes && git checkout -b master && git add .gitattributes && - git commit -m "add .gitattributes" "" && + git commit -m "add .gitattributes" . && printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONE\nLINETWO\nLINETHREE" >LF && printf "\$Id: 0000000000000000000000000000000000000000 \$\r\nLINEONE\r\nLINETWO\r\nLINETHREE" >CRLF && printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONE\r\nLINETWO\nLINETHREE" >CRLF_mix_LF && diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 0790edf60d..98e4a8613b 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -144,6 +144,11 @@ test_expect_success "check-ref-format --branch @{-1}" ' refname2=$(git check-ref-format --branch @{-2}) && test "$refname2" = master' +test_expect_success 'check-ref-format --branch -naster' ' + test_must_fail git check-ref-format --branch -naster >actual && + test_must_be_empty actual +' + test_expect_success 'check-ref-format --branch from subdir' ' mkdir subdir && @@ -161,6 +166,17 @@ test_expect_success 'check-ref-format --branch from subdir' ' test "$refname" = "$sha1" ' +test_expect_success 'check-ref-format --branch @{-1} from non-repo' ' + nongit test_must_fail git check-ref-format --branch @{-1} >actual && + test_must_be_empty actual +' + +test_expect_success 'check-ref-format --branch master from non-repo' ' + echo master >expect && + nongit git check-ref-format --branch master >actual && + test_cmp expect actual +' + valid_ref_normalized() { prereq= case $1 in diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 100d50e362..3a887b5113 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -34,6 +34,81 @@ test_update_rejected () { Q="'" +# Test adding and deleting D/F-conflicting references in a single +# transaction. +df_test() { + prefix="$1" + pack=: symadd=false symdel=false add_del=false addref= delref= + shift + while test $# -gt 0 + do + case "$1" in + --pack) + pack="git pack-refs --all" + shift + ;; + --sym-add) + # Perform the add via a symbolic reference + symadd=true + shift + ;; + --sym-del) + # Perform the del via a symbolic reference + symdel=true + shift + ;; + --del-add) + # Delete first reference then add second + add_del=false + delref="$prefix/r/$2" + addref="$prefix/r/$3" + shift 3 + ;; + --add-del) + # Add first reference then delete second + add_del=true + addref="$prefix/r/$2" + delref="$prefix/r/$3" + shift 3 + ;; + *) + echo 1>&2 "Extra args to df_test: $*" + return 1 + ;; + esac + done + git update-ref "$delref" $C && + if $symadd + then + addname="$prefix/s/symadd" && + git symbolic-ref "$addname" "$addref" + else + addname="$addref" + fi && + if $symdel + then + delname="$prefix/s/symdel" && + git symbolic-ref "$delname" "$delref" + else + delname="$delref" + fi && + cat >expected-err <<-EOF && + fatal: cannot lock ref $Q$addname$Q: $Q$delref$Q exists; cannot create $Q$addref$Q + EOF + $pack && + if $add_del + then + printf "%s\n" "create $addname $D" "delete $delname" + else + printf "%s\n" "delete $delname" "create $addname $D" + fi >commands && + test_must_fail git update-ref --stdin <commands 2>output.err && + test_cmp expected-err output.err && + printf "%s\n" "$C $delref" >expected-refs && + git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs && + test_cmp expected-refs actual-refs +} + test_expect_success 'setup' ' git commit --allow-empty -m Initial && @@ -188,6 +263,72 @@ test_expect_success 'empty directory should not fool 1-arg delete' ' git update-ref --stdin ' +test_expect_success 'D/F conflict prevents add long + delete short' ' + df_test refs/df-al-ds --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents add short + delete long' ' + df_test refs/df-as-dl --add-del foo foo/bar +' + +test_expect_success 'D/F conflict prevents delete long + add short' ' + df_test refs/df-dl-as --del-add foo/bar foo +' + +test_expect_success 'D/F conflict prevents delete short + add long' ' + df_test refs/df-ds-al --del-add foo foo/bar +' + +test_expect_success 'D/F conflict prevents add long + delete short packed' ' + df_test refs/df-al-dsp --pack --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents add short + delete long packed' ' + df_test refs/df-as-dlp --pack --add-del foo foo/bar +' + +test_expect_success 'D/F conflict prevents delete long packed + add short' ' + df_test refs/df-dlp-as --pack --del-add foo/bar foo +' + +test_expect_success 'D/F conflict prevents delete short packed + add long' ' + df_test refs/df-dsp-al --pack --del-add foo foo/bar +' + +# Try some combinations involving symbolic refs... + +test_expect_success 'D/F conflict prevents indirect add long + delete short' ' + df_test refs/df-ial-ds --sym-add --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' ' + df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' ' + df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar +' + +test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' ' + df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo +' + +test_expect_success 'D/F conflict prevents indirect add long + delete short packed' ' + df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' ' + df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents add long + indirect delete short packed' ' + df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo +' + +test_expect_success 'D/F conflict prevents indirect delete long packed + indirect add short' ' + df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo +' + # Test various errors when reading the old values of references... test_expect_success 'missing old value blocks update' ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 3704dbb2ec..6a82d1ed87 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -108,6 +108,17 @@ test_expect_success 'rebase -i with the exec command runs from tree root' ' rm -fr subdir ' +test_expect_success 'rebase -i with exec allows git commands in subdirs' ' + test_when_finished "rm -rf subdir" && + test_when_finished "git rebase --abort ||:" && + git checkout master && + mkdir subdir && (cd subdir && + set_fake_editor && + FAKE_LINES="1 exec_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \ + git rebase -i HEAD^ + ) +' + test_expect_success 'rebase -i with the exec command checks tree cleanness' ' git checkout master && set_fake_editor && diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index f8568f8841..81c6059a2d 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -858,9 +858,8 @@ test_expect_success 'rm files with two different errors' ' test_i18ncmp expect actual ' -test_expect_success 'rm empty string should invoke warning' ' - git rm -rf "" 2>output && - test_i18ngrep "warning: empty strings" output +test_expect_success 'rm empty string should fail' ' + test_must_fail git rm -rf "" ' test_done diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 0aae21d698..2748805642 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -331,9 +331,8 @@ test_expect_success 'git add --dry-run --ignore-missing of non-existing file out test_i18ncmp expect.err actual.err ' -test_expect_success 'git add empty string should invoke warning' ' - git add "" 2>output && - test_i18ngrep "warning: empty strings" output +test_expect_success 'git add empty string should fail' ' + test_must_fail git add "" ' test_expect_success 'git add --chmod=[+-]x stages correctly' ' diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 87083f728f..6c9a93b734 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -1318,30 +1318,38 @@ test_expect_success 'no effect from --color-moved with --word-diff' ' test_cmp expect actual ' -test_expect_success 'move detection ignoring whitespace ' ' +test_expect_success 'set up whitespace tests' ' git reset --hard && - cat <<\EOF >lines.txt && -line 1 -line 2 -line 3 -line 4 -long line 5 -long line 6 -long line 7 -EOF - git add lines.txt && - git commit -m "add poetry" && - cat <<\EOF >lines.txt && - long line 5 + # Note that these lines have no leading or trailing whitespace. + cat <<-\EOF >lines.txt && + line 1 + line 2 + line 3 + line 4 + line 5 long line 6 long line 7 -line 1 -line 2 -line 3 -line 4 -EOF - test_config color.diff.oldMoved "magenta" && - test_config color.diff.newMoved "cyan" && + long line 8 + long line 9 + EOF + git add lines.txt && + git commit -m "add poetry" && + git config color.diff.oldMoved "magenta" && + git config color.diff.newMoved "cyan" +' + +test_expect_success 'move detection ignoring whitespace ' ' + q_to_tab <<-\EOF >lines.txt && + Qlong line 6 + Qlong line 7 + Qlong line 8 + Qchanged long line 9 + line 1 + line 2 + line 3 + line 4 + line 5 + EOF git diff HEAD --no-renames --color-moved --color | grep -v "index" | test_decode_color >actual && @@ -1349,17 +1357,20 @@ EOF <BOLD>diff --git a/lines.txt b/lines.txt<RESET> <BOLD>--- a/lines.txt<RESET> <BOLD>+++ b/lines.txt<RESET> - <CYAN>@@ -1,7 +1,7 @@<RESET> - <GREEN>+<RESET> <GREEN>long line 5<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> <GREEN>+<RESET> <GREEN>long line 6<RESET> <GREEN>+<RESET> <GREEN>long line 7<RESET> + <GREEN>+<RESET> <GREEN>long line 8<RESET> + <GREEN>+<RESET> <GREEN>changed long line 9<RESET> line 1<RESET> line 2<RESET> line 3<RESET> line 4<RESET> - <RED>-long line 5<RESET> + line 5<RESET> <RED>-long line 6<RESET> <RED>-long line 7<RESET> + <RED>-long line 8<RESET> + <RED>-long line 9<RESET> EOF test_cmp expected actual && @@ -1370,21 +1381,160 @@ EOF <BOLD>diff --git a/lines.txt b/lines.txt<RESET> <BOLD>--- a/lines.txt<RESET> <BOLD>+++ b/lines.txt<RESET> - <CYAN>@@ -1,7 +1,7 @@<RESET> - <CYAN>+<RESET> <CYAN>long line 5<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> <CYAN>+<RESET> <CYAN>long line 6<RESET> <CYAN>+<RESET> <CYAN>long line 7<RESET> + <CYAN>+<RESET> <CYAN>long line 8<RESET> + <GREEN>+<RESET> <GREEN>changed long line 9<RESET> + line 1<RESET> + line 2<RESET> + line 3<RESET> + line 4<RESET> + line 5<RESET> + <MAGENTA>-long line 6<RESET> + <MAGENTA>-long line 7<RESET> + <MAGENTA>-long line 8<RESET> + <RED>-long line 9<RESET> + EOF + test_cmp expected actual +' + +test_expect_success 'move detection ignoring whitespace changes' ' + git reset --hard && + # Lines 6-8 have a space change, but 9 is new whitespace + q_to_tab <<-\EOF >lines.txt && + longQline 6 + longQline 7 + longQline 8 + long liQne 9 + line 1 + line 2 + line 3 + line 4 + line 5 + EOF + + git diff HEAD --no-renames --color-moved --color | + grep -v "index" | + test_decode_color >actual && + cat <<-\EOF >expected && + <BOLD>diff --git a/lines.txt b/lines.txt<RESET> + <BOLD>--- a/lines.txt<RESET> + <BOLD>+++ b/lines.txt<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> + <GREEN>+<RESET><GREEN>long line 6<RESET> + <GREEN>+<RESET><GREEN>long line 7<RESET> + <GREEN>+<RESET><GREEN>long line 8<RESET> + <GREEN>+<RESET><GREEN>long li ne 9<RESET> + line 1<RESET> + line 2<RESET> + line 3<RESET> + line 4<RESET> + line 5<RESET> + <RED>-long line 6<RESET> + <RED>-long line 7<RESET> + <RED>-long line 8<RESET> + <RED>-long line 9<RESET> + EOF + test_cmp expected actual && + + git diff HEAD --no-renames -b --color-moved --color | + grep -v "index" | + test_decode_color >actual && + cat <<-\EOF >expected && + <BOLD>diff --git a/lines.txt b/lines.txt<RESET> + <BOLD>--- a/lines.txt<RESET> + <BOLD>+++ b/lines.txt<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> + <CYAN>+<RESET><CYAN>long line 6<RESET> + <CYAN>+<RESET><CYAN>long line 7<RESET> + <CYAN>+<RESET><CYAN>long line 8<RESET> + <GREEN>+<RESET><GREEN>long li ne 9<RESET> + line 1<RESET> + line 2<RESET> + line 3<RESET> + line 4<RESET> + line 5<RESET> + <MAGENTA>-long line 6<RESET> + <MAGENTA>-long line 7<RESET> + <MAGENTA>-long line 8<RESET> + <RED>-long line 9<RESET> + EOF + test_cmp expected actual +' + +test_expect_success 'move detection ignoring whitespace at eol' ' + git reset --hard && + # Lines 6-9 have new eol whitespace, but 9 also has it in the middle + q_to_tab <<-\EOF >lines.txt && + long line 6Q + long line 7Q + long line 8Q + longQline 9Q + line 1 + line 2 + line 3 + line 4 + line 5 + EOF + + # avoid cluttering the output with complaints about our eol whitespace + test_config core.whitespace -blank-at-eol && + + git diff HEAD --no-renames --color-moved --color | + grep -v "index" | + test_decode_color >actual && + cat <<-\EOF >expected && + <BOLD>diff --git a/lines.txt b/lines.txt<RESET> + <BOLD>--- a/lines.txt<RESET> + <BOLD>+++ b/lines.txt<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> + <GREEN>+<RESET><GREEN>long line 6 <RESET> + <GREEN>+<RESET><GREEN>long line 7 <RESET> + <GREEN>+<RESET><GREEN>long line 8 <RESET> + <GREEN>+<RESET><GREEN>long line 9 <RESET> + line 1<RESET> + line 2<RESET> + line 3<RESET> + line 4<RESET> + line 5<RESET> + <RED>-long line 6<RESET> + <RED>-long line 7<RESET> + <RED>-long line 8<RESET> + <RED>-long line 9<RESET> + EOF + test_cmp expected actual && + + git diff HEAD --no-renames --ignore-space-at-eol --color-moved --color | + grep -v "index" | + test_decode_color >actual && + cat <<-\EOF >expected && + <BOLD>diff --git a/lines.txt b/lines.txt<RESET> + <BOLD>--- a/lines.txt<RESET> + <BOLD>+++ b/lines.txt<RESET> + <CYAN>@@ -1,9 +1,9 @@<RESET> + <CYAN>+<RESET><CYAN>long line 6 <RESET> + <CYAN>+<RESET><CYAN>long line 7 <RESET> + <CYAN>+<RESET><CYAN>long line 8 <RESET> + <GREEN>+<RESET><GREEN>long line 9 <RESET> line 1<RESET> line 2<RESET> line 3<RESET> line 4<RESET> - <MAGENTA>-long line 5<RESET> + line 5<RESET> <MAGENTA>-long line 6<RESET> <MAGENTA>-long line 7<RESET> + <MAGENTA>-long line 8<RESET> + <RED>-long line 9<RESET> EOF test_cmp expected actual ' +test_expect_success 'clean up whitespace-test colors' ' + git config --unset color.diff.oldMoved && + git config --unset color.diff.newMoved +' + test_expect_success '--color-moved block at end of diff output respects MIN_ALNUM_COUNT' ' git reset --hard && >bar && @@ -1530,13 +1680,4 @@ test_expect_success 'move detection with submodules' ' test_cmp expect decoded_actual ' -test_expect_success 'move detection with whitespace changes' ' - test_when_finished "git reset --hard" && - test_seq 10 >test && - git add test && - sed s/3/42/ <test >test.tmp && - mv test.tmp test && - git -c diff.colormoved diff --ignore-space-change -- test -' - test_done diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index ded8f98dbe..c19d8dbc9d 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -165,4 +165,49 @@ test_expect_success 'git pull --allow-unrelated-histories' ' ) ' +test_expect_success 'git pull does not add a sign-off line' ' + test_when_finished "rm -fr src dst actual" && + git init src && + test_commit -C src one && + git clone src dst && + test_commit -C src two && + git -C dst pull --no-ff && + git -C dst show -s --pretty="format:%(trailers)" HEAD >actual && + test_must_be_empty actual +' + +test_expect_success 'git pull --no-signoff does not add sign-off line' ' + test_when_finished "rm -fr src dst actual" && + git init src && + test_commit -C src one && + git clone src dst && + test_commit -C src two && + git -C dst pull --no-signoff --no-ff && + git -C dst show -s --pretty="format:%(trailers)" HEAD >actual && + test_must_be_empty actual +' + +test_expect_success 'git pull --signoff add a sign-off line' ' + test_when_finished "rm -fr src dst expected actual" && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected && + git init src && + test_commit -C src one && + git clone src dst && + test_commit -C src two && + git -C dst pull --signoff --no-ff && + git -C dst show -s --pretty="format:%(trailers)" HEAD >actual && + test_cmp expected actual +' + +test_expect_success 'git pull --no-signoff flag cancels --signoff flag' ' + test_when_finished "rm -fr src dst actual" && + git init src && + test_commit -C src one && + git clone src dst && + test_commit -C src two && + git -C dst pull --signoff --no-signoff --no-ff && + git -C dst show -s --pretty="format:%(trailers)" HEAD >actual && + test_must_be_empty actual +' + test_done diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 42251f7f3a..a552ad4ead 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -478,7 +478,47 @@ test_expect_success "don't fetch submodule when newly recorded commits are alrea git fetch >../actual.out 2>../actual.err ) && ! test -s actual.out && - test_i18ncmp expect.err actual.err + test_i18ncmp expect.err actual.err && + ( + cd submodule && + git checkout -q master + ) +' + +test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .gitmodule entry" ' + ( + cd downstream && + git fetch --recurse-submodules + ) && + add_upstream_commit && + head1=$(git rev-parse --short HEAD) && + git add submodule && + git rm .gitmodules && + git commit -m "new submodule without .gitmodules" && + printf "" >expect.out && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." >expect.err.2 && + echo " $head1..$head2 master -> origin/master" >>expect.err.2 && + head -3 expect.err >>expect.err.2 && + ( + cd downstream && + rm .gitmodules && + git config fetch.recurseSubmodules on-demand && + # fake submodule configuration to avoid skipping submodule handling + git config -f .gitmodules submodule.fake.path fake && + git config -f .gitmodules submodule.fake.url fakeurl && + git add .gitmodules && + git config --unset submodule.submodule.url && + git fetch >../actual.out 2>../actual.err && + # cleanup + git config --unset fetch.recurseSubmodules && + git reset --hard + ) && + test_i18ncmp expect.out actual.out && + test_i18ncmp expect.err.2 actual.err && + git checkout HEAD^ -- .gitmodules && + git add .gitmodules && + git commit -m "new submodule restored .gitmodules" ' test_expect_success 'fetching submodules respects parallel settings' ' @@ -530,4 +570,39 @@ test_expect_success 'fetching submodule into a broken repository' ' test_must_fail git -C dst fetch --recurse-submodules ' +test_expect_success "fetch new commits when submodule got renamed" ' + git clone . downstream_rename && + ( + cd downstream_rename && + git submodule update --init && +# NEEDSWORK: we omitted --recursive for the submodule update here since +# that does not work. See test 7001 for mv "moving nested submodules" +# for details. Once that is fixed we should add the --recursive option +# here. + git checkout -b rename && + git mv submodule submodule_renamed && + ( + cd submodule_renamed && + git checkout -b rename_sub && + echo a >a && + git add a && + git commit -ma && + git push origin rename_sub && + git rev-parse HEAD >../../expect + ) && + git add submodule_renamed && + git commit -m "update renamed submodule" && + git push origin rename + ) && + ( + cd downstream && + git fetch --recurse-submodules=on-demand && + ( + cd submodule && + git rev-parse origin/rename_sub >../../actual + ) + ) && + test_cmp expect actual +' + test_done diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh index 90a4b0d2fe..463783789c 100755 --- a/t/t5545-push-options.sh +++ b/t/t5545-push-options.sh @@ -140,6 +140,83 @@ test_expect_success 'push options and submodules' ' test_cmp expect parent_upstream/.git/hooks/post-receive.push_options ' +test_expect_success 'default push option' ' + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + git -c push.pushOption=default push up master + ) && + test_refs master master && + echo "default" >expect && + test_cmp expect upstream/.git/hooks/pre-receive.push_options && + test_cmp expect upstream/.git/hooks/post-receive.push_options +' + +test_expect_success 'two default push options' ' + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + git -c push.pushOption=default1 -c push.pushOption=default2 push up master + ) && + test_refs master master && + printf "default1\ndefault2\n" >expect && + test_cmp expect upstream/.git/hooks/pre-receive.push_options && + test_cmp expect upstream/.git/hooks/post-receive.push_options +' + +test_expect_success 'push option from command line overrides from-config push option' ' + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + git -c push.pushOption=default push --push-option=manual up master + ) && + test_refs master master && + echo "manual" >expect && + test_cmp expect upstream/.git/hooks/pre-receive.push_options && + test_cmp expect upstream/.git/hooks/post-receive.push_options +' + +test_expect_success 'empty value of push.pushOption in config clears the list' ' + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + git -c push.pushOption=default1 -c push.pushOption= -c push.pushOption=default2 push up master + ) && + test_refs master master && + echo "default2" >expect && + test_cmp expect upstream/.git/hooks/pre-receive.push_options && + test_cmp expect upstream/.git/hooks/post-receive.push_options +' + +test_expect_success 'invalid push option in config' ' + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + test_must_fail git -c push.pushOption push up master + ) && + test_refs master HEAD@{1} +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 9c56f771b6..50e40abb11 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -308,6 +308,7 @@ test_expect_success 'clone checking out a tag' ' setup_ssh_wrapper () { test_expect_success 'setup ssh wrapper' ' + rm -f "$TRASH_DIRECTORY/ssh-wrapper$X" && cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \ "$TRASH_DIRECTORY/ssh-wrapper$X" && GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" && @@ -318,6 +319,7 @@ setup_ssh_wrapper () { } copy_ssh_wrapper_as () { + rm -f "${1%$X}$X" && cp "$TRASH_DIRECTORY/ssh-wrapper$X" "${1%$X}$X" && GIT_SSH="${1%$X}$X" && export GIT_SSH diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 8c2c6eaef8..f84ff941c3 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -894,4 +894,21 @@ test_expect_success 'bisect start takes options and revs in any order' ' test_cmp expected actual ' +test_expect_success 'git bisect reset cleans bisection state properly' ' + git bisect reset && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + git bisect reset && + test -z "$(git for-each-ref "refs/bisect/*")" && + test_path_is_missing "$GIT_DIR/BISECT_EXPECTED_REV" && + test_path_is_missing "$GIT_DIR/BISECT_ANCESTORS_OK" && + test_path_is_missing "$GIT_DIR/BISECT_LOG" && + test_path_is_missing "$GIT_DIR/BISECT_RUN" && + test_path_is_missing "$GIT_DIR/BISECT_TERMS" && + test_path_is_missing "$GIT_DIR/head-name" && + test_path_is_missing "$GIT_DIR/BISECT_HEAD" && + test_path_is_missing "$GIT_DIR/BISECT_START" +' + test_done diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index f0f1abd1c2..865168ec6a 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -570,4 +570,18 @@ test_expect_success 'command with underscores does not complain' ' test_cmp expect actual ' +test_expect_success TTY 'git tag with auto-columns ' ' + test_commit one && + test_commit two && + test_commit three && + test_commit four && + test_commit five && + cat >expect <<-\EOF && + initial one two three four five + EOF + test_terminal env PAGER="cat >actual" COLUMNS=80 \ + git -c column.ui=auto tag --sort=authordate && + test_cmp expect actual +' + test_done diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh index fc6013ba3c..0c394cf995 100755 --- a/t/t7061-wtstatus-ignore.sh +++ b/t/t7061-wtstatus-ignore.sh @@ -272,4 +272,15 @@ test_expect_success 'status ignored tracked directory with uncommitted file in t test_cmp expected actual ' +cat >expected <<\EOF +!! tracked/submodule/ +EOF + +test_expect_success 'status ignores submodule in excluded directory' ' + git init tracked/submodule && + test_commit -C tracked/submodule initial && + git status --porcelain --ignored -u tracked/submodule >actual && + test_cmp expected actual +' + test_done diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh new file mode 100755 index 0000000000..634fb7f23a --- /dev/null +++ b/t/t7520-ignored-hook-warning.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +test_description='ignored hook warning' + +. ./test-lib.sh + +test_expect_success setup ' + hookdir="$(git rev-parse --git-dir)/hooks" && + hook="$hookdir/pre-commit" && + mkdir -p "$hookdir" && + write_script "$hook" <<-\EOF + exit 0 + EOF +' + +test_expect_success 'no warning if hook is not ignored' ' + git commit --allow-empty -m "more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_expect_success POSIXPERM 'warning if hook is ignored' ' + chmod -x "$hook" && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep -e "hook was ignored" message +' + +test_expect_success POSIXPERM 'no warning if advice.ignoredHook set to false' ' + test_config advice.ignoredHook false && + chmod -x "$hook" && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_expect_success 'no warning if unset advice.ignoredHook and hook removed' ' + rm -f "$hook" && + test_unconfig advice.ignoredHook && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_done diff --git a/tempfile.h b/tempfile.h index b8f4b5e145..450908b2e0 100644 --- a/tempfile.h +++ b/tempfile.h @@ -68,10 +68,10 @@ * `create_tempfile()` returns an allocated tempfile on success or NULL * on failure. On errors, `errno` describes the reason for failure. * - * `delete_tempfile()`, `rename_tempfile()`, and `close_tempfile_gently()` - * return 0 on success. On failure they set `errno` appropriately and return - * -1. `delete` and `rename` (but not `close`) do their best to delete the - * temporary file before returning. + * `rename_tempfile()` and `close_tempfile_gently()` return 0 on success. + * On failure they set `errno` appropriately and return -1. + * `delete_tempfile()` and `rename` (but not `close`) do their best to + * delete the temporary file before returning. */ struct tempfile { diff --git a/transport-helper.c b/transport-helper.c index c948d5215c..bf05a2dcf1 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -535,7 +535,7 @@ static int fetch_with_import(struct transport *transport, else private = xstrdup(name); if (private) { - if (read_ref(private, posn->old_oid.hash) < 0) + if (read_ref(private, &posn->old_oid) < 0) die("Could not read ref %s", private); free(private); } @@ -795,7 +795,8 @@ static int push_update_refs_status(struct helper_data *data, private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name); if (!private) continue; - update_ref("update by helper", private, ref->new_oid.hash, NULL, 0, 0); + update_ref("update by helper", private, &ref->new_oid, NULL, + 0, 0); free(private); } strbuf_release(&buf); @@ -941,10 +942,9 @@ static int push_refs_with_export(struct transport *transport, int flag; /* Follow symbolic refs (mainly for HEAD). */ - name = resolve_ref_unsafe( - ref->peer_ref->name, - RESOLVE_REF_READING, - oid.hash, &flag); + name = resolve_ref_unsafe(ref->peer_ref->name, + RESOLVE_REF_READING, + &oid, &flag); if (!name || !(flag & REF_ISSYMREF)) name = ref->peer_ref->name; @@ -1066,8 +1066,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) if (eon) { if (has_attribute(eon + 1, "unchanged")) { (*tail)->status |= REF_STATUS_UPTODATE; - if (read_ref((*tail)->name, - (*tail)->old_oid.hash) < 0) + if (read_ref((*tail)->name, &(*tail)->old_oid) < 0) die(_("Could not read ref %s"), (*tail)->name); } diff --git a/transport.c b/transport.c index f1e2f61991..7231d1b1b0 100644 --- a/transport.c +++ b/transport.c @@ -305,8 +305,8 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v if (ref->deletion) { delete_ref(NULL, rs.dst, NULL, 0); } else - update_ref("update by push", rs.dst, - ref->new_oid.hash, NULL, 0, 0); + update_ref("update by push", rs.dst, &ref->new_oid, + NULL, 0, 0); free(rs.dst); } } diff --git a/unpack-trees.c b/unpack-trees.c index 71b70ccb12..25740cb593 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1541,15 +1541,15 @@ static int verify_clean_subdirectory(const struct cache_entry *ce, int cnt = 0; if (S_ISGITLINK(ce->ce_mode)) { - unsigned char sha1[20]; - int sub_head = resolve_gitlink_ref(ce->name, "HEAD", sha1); + struct object_id oid; + int sub_head = resolve_gitlink_ref(ce->name, "HEAD", &oid); /* * If we are not going to update the submodule, then * we don't care. */ - if (!sub_head && !hashcmp(sha1, ce->oid.hash)) + if (!sub_head && !oidcmp(&oid, &ce->oid)) return 0; - return verify_clean_submodule(sub_head ? NULL : sha1_to_hex(sha1), + return verify_clean_submodule(sub_head ? NULL : oid_to_hex(&oid), ce, error_type, o); } diff --git a/upload-pack.c b/upload-pack.c index e25f725c0f..6d5f3c0d39 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -787,7 +787,7 @@ static void receive_needs(void) if (skip_prefix(line, "deepen-not ", &arg)) { char *ref = NULL; struct object_id oid; - if (expand_ref(arg, strlen(arg), oid.hash, &ref) != 1) + if (expand_ref(arg, strlen(arg), &oid, &ref) != 1) die("git upload-pack: ambiguous deepen-not: %s", line); string_list_append(&deepen_not, ref); free(ref); @@ -955,7 +955,7 @@ static int send_ref(const char *refname, const struct object_id *oid, packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), refname_nons); } capabilities = NULL; - if (!peel_ref(refname, peeled.hash)) + if (!peel_ref(refname, &peeled)) packet_write_fmt(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons); return 0; } @@ -7,7 +7,7 @@ #include "blob.h" #include "refs.h" -static unsigned char current_commit_sha1[20]; +static struct object_id current_commit_oid; void walker_say(struct walker *walker, const char *fmt, ...) { @@ -24,9 +24,9 @@ static void report_missing(const struct object *obj) fprintf(stderr, "Cannot obtain needed %s %s\n", obj->type ? typename(obj->type): "object", oid_to_hex(&obj->oid)); - if (!is_null_sha1(current_commit_sha1)) + if (!is_null_oid(¤t_commit_oid)) fprintf(stderr, "while processing commit %s.\n", - sha1_to_hex(current_commit_sha1)); + oid_to_hex(¤t_commit_oid)); } static int process(struct walker *walker, struct object *obj); @@ -82,7 +82,7 @@ static int process_commit(struct walker *walker, struct commit *commit) if (commit->object.flags & COMPLETE) return 0; - hashcpy(current_commit_sha1, commit->object.oid.hash); + oidcpy(¤t_commit_oid, &commit->object.oid); walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid)); @@ -187,14 +187,14 @@ static int loop(struct walker *walker) return 0; } -static int interpret_target(struct walker *walker, char *target, unsigned char *sha1) +static int interpret_target(struct walker *walker, char *target, struct object_id *oid) { - if (!get_sha1_hex(target, sha1)) + if (!get_oid_hex(target, oid)) return 0; if (!check_refname_format(target, 0)) { struct ref *ref = alloc_ref(target); if (!walker->fetch_ref(walker, ref)) { - hashcpy(sha1, ref->old_oid.hash); + oidcpy(oid, &ref->old_oid); free(ref); return 0; } @@ -259,7 +259,7 @@ int walker_fetch(struct walker *walker, int targets, char **target, struct strbuf refname = STRBUF_INIT; struct strbuf err = STRBUF_INIT; struct ref_transaction *transaction = NULL; - unsigned char *sha1 = xmalloc(targets * 20); + struct object_id *oids = xmalloc(targets * sizeof(struct object_id)); char *msg = NULL; int i, ret = -1; @@ -279,11 +279,11 @@ int walker_fetch(struct walker *walker, int targets, char **target, } for (i = 0; i < targets; i++) { - if (interpret_target(walker, target[i], &sha1[20 * i])) { + if (interpret_target(walker, target[i], oids + i)) { error("Could not interpret response from server '%s' as something to pull", target[i]); goto done; } - if (process(walker, lookup_unknown_object(&sha1[20 * i]))) + if (process(walker, lookup_unknown_object(oids[i].hash))) goto done; } @@ -304,7 +304,7 @@ int walker_fetch(struct walker *walker, int targets, char **target, strbuf_reset(&refname); strbuf_addf(&refname, "refs/%s", write_ref[i]); if (ref_transaction_update(transaction, refname.buf, - &sha1[20 * i], NULL, 0, + oids + i, NULL, 0, msg ? msg : "fetch (unknown)", &err)) { error("%s", err.buf); @@ -321,7 +321,7 @@ int walker_fetch(struct walker *walker, int targets, char **target, done: ref_transaction_free(transaction); free(msg); - free(sha1); + free(oids); strbuf_release(&err); strbuf_release(&refname); return ret; diff --git a/worktree.c b/worktree.c index 70015629dc..f5da7d286d 100644 --- a/worktree.c +++ b/worktree.c @@ -31,7 +31,7 @@ static void add_head_info(struct worktree *wt) target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt), "HEAD", 0, - wt->head_sha1, &flags); + &wt->head_oid, &flags); if (!target) return; @@ -327,7 +327,8 @@ const struct worktree *find_shared_symref(const char *symref, refs = get_worktree_ref_store(wt); symref_target = refs_resolve_ref_unsafe(refs, symref, 0, NULL, &flags); - if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) { + if ((flags & REF_ISSYMREF) && + symref_target && !strcmp(symref_target, target)) { existing = wt; break; } diff --git a/worktree.h b/worktree.h index 9276c81ae7..c28a880e18 100644 --- a/worktree.h +++ b/worktree.h @@ -8,7 +8,7 @@ struct worktree { char *id; char *head_ref; /* NULL if HEAD is broken or detached */ char *lock_reason; /* internal use */ - unsigned char head_sha1[20]; + struct object_id head_oid; int is_detached; int is_bare; int is_current; diff --git a/wt-status.c b/wt-status.c index 29bc64cc02..bedef256ce 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1449,7 +1449,7 @@ static void wt_status_get_detached_from(struct wt_status_state *state) return; } - if (dwim_ref(cb.buf.buf, cb.buf.len, oid.hash, &ref) == 1 && + if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 && /* sha1 is a commit? match without further lookup */ (!oidcmp(&cb.noid, &oid) || /* perhaps sha1 is a tag, try to dereference to a commit */ @@ -2297,14 +2297,14 @@ int has_uncommitted_changes(int ignore_submodules) */ int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently) { - struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file)); + struct lock_file lock_file = LOCK_INIT; int err = 0, fd; - fd = hold_locked_index(lock_file, 0); + fd = hold_locked_index(&lock_file, 0); refresh_cache(REFRESH_QUIET); if (0 <= fd) - update_index_if_able(&the_index, lock_file); - rollback_lock_file(lock_file); + update_index_if_able(&the_index, &lock_file); + rollback_lock_file(&lock_file); if (has_unstaged_changes(ignore_submodules)) { /* TRANSLATORS: the action is e.g. "pull with rebase" */ diff --git a/xdiff-interface.c b/xdiff-interface.c index 018e033089..770e1f7f81 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -5,6 +5,7 @@ #include "xdiff/xdiffi.h" #include "xdiff/xemit.h" #include "xdiff/xmacros.h" +#include "xdiff/xutils.h" struct xdiff_emit_state { xdiff_emit_consume_fn consume; @@ -296,6 +297,17 @@ void xdiff_clear_find_func(xdemitconf_t *xecfg) } } +unsigned long xdiff_hash_string(const char *s, size_t len, long flags) +{ + return xdl_hash_record(&s, s + len, flags); +} + +int xdiff_compare_lines(const char *l1, long s1, + const char *l2, long s2, long flags) +{ + return xdl_recmatch(l1, s1, l2, s2, flags); +} + int git_xmerge_style = -1; int git_xmerge_config(const char *var, const char *value, void *cb) diff --git a/xdiff-interface.h b/xdiff-interface.h index 6f6ba9095d..135fc05d72 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -29,4 +29,20 @@ extern void xdiff_clear_find_func(xdemitconf_t *xecfg); extern int git_xmerge_config(const char *var, const char *value, void *cb); extern int git_xmerge_style; +/* + * Compare the strings l1 with l2 which are of size s1 and s2 respectively. + * Returns 1 if the strings are deemed equal, 0 otherwise. + * The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces + * are treated for the comparision. + */ +extern int xdiff_compare_lines(const char *l1, long s1, + const char *l2, long s2, long flags); + +/* + * Returns a hash of the string s of length len. + * The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces + * are treated for the hash. + */ +extern unsigned long xdiff_hash_string(const char *s, size_t len, long flags); + #endif |