diff options
58 files changed, 658 insertions, 305 deletions
diff --git a/Documentation/RelNotes/1.7.6.1.txt b/Documentation/RelNotes/1.7.6.1.txt index 95905e48f8..42e46ab17f 100644 --- a/Documentation/RelNotes/1.7.6.1.txt +++ b/Documentation/RelNotes/1.7.6.1.txt @@ -12,6 +12,8 @@ Fixes since v1.7.6 though the actual error was that "unexecutable" was found but did not have a proper she-bang line to be executed. + * Error exits from $PAGER were silently ignored. + * "git checkout -b <branch>" was confused when attempting to create a branch whose name ends with "-g" followed by hexadecimal digits, and refused to work. @@ -21,9 +23,16 @@ Fixes since v1.7.6 * "git diff --cc" learned to correctly ignore binary files. + * "git diff -c/--cc" mishandled a deletion that resolves a conflict, and + looked in the working tree instead. + * "git fast-export" forgot to quote pathnames with unsafe characters in its output. + * "git fetch" over smart-http transport used to abort when the + repository was updated between the initial connection and the + subsequent object transfer. + * "git fetch" did not recurse into submodules in subdirectories. * "git ls-tree" did not error out when asked to show a corrupt tree. @@ -31,6 +40,8 @@ Fixes since v1.7.6 * "git pull" without any argument left an extra whitespace after the command name in its reflog. + * "git push --quiet" was not really quiet. + * "git rebase -i -p" incorrectly dropped commits from side branches. * "git reset [<commit>] paths..." did not reset the index entry correctly diff --git a/Documentation/RelNotes/1.7.7.txt b/Documentation/RelNotes/1.7.7.txt index 28214e2721..dcbda84e86 100644 --- a/Documentation/RelNotes/1.7.7.txt +++ b/Documentation/RelNotes/1.7.7.txt @@ -19,6 +19,11 @@ Updates since v1.7.6 functions can compress or uncompress more than 4GB data in one call on platforms with 64-bit long, which has been corrected. + * Git now recognizes loose objects written by other implementations that + uses non-standard window size for zlib deflation (e.g. Agit running on + Android with 4kb window). We used to reject anything that was not + deflated with 32kb window. + * "git am" learned to pass "--exclude=<path>" option through to underlying "git apply". @@ -98,25 +103,14 @@ Fixes since v1.7.6 Unless otherwise noted, all the fixes in 1.7.6.X maintenance track are included in this release. - * Error exits from $PAGER were silently ignored. - (merge fc1b56f cb/maint-exec-error-report later). - - * "git diff -c/--cc" mishandled a deletion that resolves a conflict, and - looked in the working tree instead. - (merge 9969454 jc/maint-combined-diff-work-tree later). - - * "git fetch" over smart-http transport used to abort when the - repository was updated between the initial connection and the - subsequent object transfer. - (merge 051e400 jc/maint-smart-http-race-upload-pack later). - - * "git push --quiet" was not really quiet. - (merge 0d086b8 cb/maint-quiet-push later). + * "ls-files ../$path" that is run from a subdirectory reported errors + incorrectly when there is no such path that matches the given pathspec. + (merge 0f64bfa cb/maint-ls-files-error-report later to 'maint'). -- exec >/var/tmp/1 echo O=$(git describe master) -O=v1.7.6-548-g324b6b1 +O=v1.7.6-576-g6fcb384 git log --first-parent --oneline $O..master echo git shortlog --no-merges ^maint ^$O master diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 2969388880..db0d75fdbc 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -1012,10 +1012,14 @@ force:: (see OPTIONS, above). import-marks:: +import-marks-if-exists:: Like --import-marks except in two respects: first, only one - "feature import-marks" command is allowed per stream; - second, an --import-marks= command-line option overrides - any "feature import-marks" command in the stream. + "feature import-marks" or "feature import-marks-if-exists" + command is allowed per stream; second, an --import-marks= + or --import-marks-if-exists command-line option overrides + any of these "feature" commands in the stream; third, + "feature import-marks-if-exists" like a corresponding + command-line option silently skips a nonexistent file. cat-blob:: ls:: diff --git a/Documentation/git.txt b/Documentation/git.txt index 710d750cfd..d08a8bb4f2 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.6/git.html[documentation for release 1.7.6] +* link:v1.7.6.1/git.html[documentation for release 1.7.6.1] * release notes for + link:RelNotes/1.7.6.1.txt[1.7.6.1]. link:RelNotes/1.7.6.txt[1.7.6]. * link:v1.7.5.4/git.html[documentation for release 1.7.5.4] diff --git a/Documentation/technical/api-ref-iteration.txt b/Documentation/technical/api-ref-iteration.txt new file mode 100644 index 0000000000..dbbea95db7 --- /dev/null +++ b/Documentation/technical/api-ref-iteration.txt @@ -0,0 +1,81 @@ +ref iteration API +================= + + +Iteration of refs is done by using an iterate function which will call a +callback function for every ref. The callback function has this +signature: + + int handle_one_ref(const char *refname, const unsigned char *sha1, + int flags, void *cb_data); + +There are different kinds of iterate functions which all take a +callback of this type. The callback is then called for each found ref +until the callback returns nonzero. The returned value is then also +returned by the iterate function. + +Iteration functions +------------------- + +* `head_ref()` just iterates the head ref. + +* `for_each_ref()` iterates all refs. + +* `for_each_ref_in()` iterates all refs which have a defined prefix and + strips that prefix from the passed variable refname. + +* `for_each_tag_ref()`, `for_each_branch_ref()`, `for_each_remote_ref()`, + `for_each_replace_ref()` iterate refs from the respective area. + +* `for_each_glob_ref()` iterates all refs that match the specified glob + pattern. + +* `for_each_glob_ref_in()` the previous and `for_each_ref_in()` combined. + +* `head_ref_submodule()`, `for_each_ref_submodule()`, + `for_each_ref_in_submodule()`, `for_each_tag_ref_submodule()`, + `for_each_branch_ref_submodule()`, `for_each_remote_ref_submodule()` + do the same as the functions descibed above but for a specified + submodule. + +* `for_each_rawref()` can be used to learn about broken ref and symref. + +* `for_each_reflog()` iterates each reflog file. + +Submodules +---------- + +If you want to iterate the refs of a submodule you first need to add the +submodules object database. You can do this by a code-snippet like +this: + + const char *path = "path/to/submodule" + if (!add_submodule_odb(path)) + die("Error submodule '%s' not populated.", path); + +`add_submodule_odb()` will return an non-zero value on success. If you +do not do this you will get an error for each ref that it does not point +to a valid object. + +Note: As a side-effect of this you can not safely assume that all +objects you lookup are available in superproject. All submodule objects +will be available the same way as the superprojects objects. + +Example: +-------- + +---- +static int handle_remote_ref(const char *refname, + const unsigned char *sha1, int flags, void *cb_data) +{ + struct strbuf *output = cb_data; + strbuf_addf(output, "%s\n", refname); + return 0; +} + +... + + struct strbuf output = STRBUF_INIT; + for_each_remote_ref(handle_remote_ref, &output); + printf("%s", output.buf); +---- @@ -643,6 +643,7 @@ LIB_OBJS += pack-revindex.o LIB_OBJS += pack-write.o LIB_OBJS += pager.o LIB_OBJS += parse-options.o +LIB_OBJS += parse-options-cb.o LIB_OBJS += patch-delta.o LIB_OBJS += patch-ids.o LIB_OBJS += path.o @@ -2205,7 +2206,7 @@ test-delta$X: diff-delta.o patch-delta.o test-line-buffer$X: vcs-svn/lib.a -test-parse-options$X: parse-options.o +test-parse-options$X: parse-options.o parse-options-cb.o test-string-pool$X: vcs-svn/lib.a @@ -139,3 +139,31 @@ const char *absolute_path(const char *path) } return buf; } + +/* + * Unlike prefix_path, this should be used if the named file does + * not have to interact with index entry; i.e. name of a random file + * on the filesystem. + */ +const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) +{ + static char path[PATH_MAX]; +#ifndef WIN32 + if (!pfx_len || is_absolute_path(arg)) + return arg; + memcpy(path, pfx, pfx_len); + strcpy(path + pfx_len, arg); +#else + char *p; + /* don't add prefix to absolute paths, but still replace '\' by '/' */ + if (is_absolute_path(arg)) + pfx_len = 0; + else if (pfx_len) + memcpy(path, pfx, pfx_len); + strcpy(path + pfx_len, arg); + for (p = path + pfx_len; *p; p++) + if (*p == '\\') + *p = '/'; +#endif + return path; +} diff --git a/builtin/checkout.c b/builtin/checkout.c index d647a31303..4eaedff0c4 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -201,7 +201,7 @@ static int checkout_merged(int pos, struct checkout *state) } static int checkout_paths(struct tree *source_tree, const char **pathspec, - struct checkout_opts *opts) + const char *prefix, struct checkout_opts *opts) { int pos; struct checkout state; @@ -231,7 +231,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched); } - if (report_path_error(ps_matched, pathspec, 0)) + if (report_path_error(ps_matched, pathspec, prefix)) return 1; /* "checkout -m path" to recreate conflicted state */ @@ -1064,7 +1064,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge) die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.")); - return checkout_paths(source_tree, pathspec, &opts); + return checkout_paths(source_tree, pathspec, prefix, &opts); } if (patch_mode) diff --git a/builtin/commit.c b/builtin/commit.c index cb738574f7..05029d40d1 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -62,8 +62,6 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\ "\n" "Otherwise, please use 'git reset'\n"); -static unsigned char head_sha1[20]; - static const char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ @@ -102,7 +100,7 @@ static enum { static char *cleanup_arg; static enum commit_whence whence; -static int use_editor = 1, initial_commit, include_status = 1; +static int use_editor = 1, include_status = 1; static int show_ignored_in_status; static const char *only_include_assumed; static struct strbuf message; @@ -274,7 +272,7 @@ static int list_paths(struct string_list *list, const char *with_tree, item->util = item; /* better a valid pointer than a fake one */ } - return report_path_error(m, pattern, prefix ? strlen(prefix) : 0); + return report_path_error(m, pattern, prefix); } static void add_remove_files(struct string_list *list) @@ -296,13 +294,13 @@ static void add_remove_files(struct string_list *list) } } -static void create_base_index(void) +static void create_base_index(const struct commit *current_head) { struct tree *tree; struct unpack_trees_options opts; struct tree_desc t; - if (initial_commit) { + if (!current_head) { discard_cache(); return; } @@ -315,7 +313,7 @@ static void create_base_index(void) opts.dst_index = &the_index; opts.fn = oneway_merge; - tree = parse_tree_indirect(head_sha1); + tree = parse_tree_indirect(current_head->object.sha1); if (!tree) die(_("failed to unpack HEAD tree object")); parse_tree(tree); @@ -334,7 +332,8 @@ static void refresh_cache_or_die(int refresh_flags) die_resolve_conflict("commit"); } -static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status) +static char *prepare_index(int argc, const char **argv, const char *prefix, + const struct commit *current_head, int is_status) { int fd; struct string_list partial; @@ -450,7 +449,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int memset(&partial, 0, sizeof(partial)); partial.strdup_strings = 1; - if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec)) + if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec)) exit(1); discard_cache(); @@ -469,7 +468,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int (uintmax_t) getpid()), LOCK_DIE_ON_ERROR); - create_base_index(); + create_base_index(current_head); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); @@ -518,12 +517,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int return s->commitable; } -static int is_a_merge(const unsigned char *sha1) +static int is_a_merge(const struct commit *current_head) { - struct commit *commit = lookup_commit(sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - return !!(commit->parents && commit->parents->next); + return !!(current_head->parents && current_head->parents->next); } static const char sign_off_header[] = "Signed-off-by: "; @@ -627,6 +623,7 @@ static char *cut_ident_timestamp_part(char *string) } static int prepare_to_commit(const char *index_file, const char *prefix, + struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { @@ -848,7 +845,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && - !(amend && is_a_merge(head_sha1))) { + !(amend && is_a_merge(current_head))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); @@ -1006,6 +1003,7 @@ static const char *read_commit_message(const char *name) static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, + struct commit *current_head, struct wt_status *s) { int f = 0; @@ -1026,11 +1024,8 @@ static int parse_and_validate_options(int argc, const char *argv[], if (!use_editor) setenv("GIT_EDITOR", ":", 1); - if (get_sha1("HEAD", head_sha1)) - initial_commit = 1; - /* Sanity check options */ - if (amend && initial_commit) + if (amend && !current_head) die(_("You have nothing to amend.")); if (amend && whence != FROM_COMMIT) die(_("You are in the middle of a %s -- cannot amend."), whence_s()); @@ -1102,12 +1097,12 @@ static int parse_and_validate_options(int argc, const char *argv[], } static int dry_run_commit(int argc, const char **argv, const char *prefix, - struct wt_status *s) + const struct commit *current_head, struct wt_status *s) { int commitable; const char *index_file; - index_file = prepare_index(argc, argv, prefix, 1); + index_file = prepare_index(argc, argv, prefix, current_head, 1); commitable = run_status(stdout, index_file, prefix, 0, s); rollback_index_files(); @@ -1260,7 +1255,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) return 0; } -static void print_summary(const char *prefix, const unsigned char *sha1) +static void print_summary(const char *prefix, const unsigned char *sha1, + int initial_commit) { struct rev_info rev; struct commit *commit; @@ -1382,12 +1378,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct strbuf author_ident = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; - unsigned char commit_sha1[20]; + unsigned char sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; struct wt_status s; + struct commit *current_head = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1398,38 +1395,41 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (s.use_color == -1) s.use_color = git_use_color_default; + if (get_sha1("HEAD", sha1)) + current_head = NULL; + else { + current_head = lookup_commit(sha1); + if (!current_head || parse_commit(current_head)) + die(_("could not parse HEAD commit")); + } argc = parse_and_validate_options(argc, argv, builtin_commit_usage, - prefix, &s); + prefix, current_head, &s); if (dry_run) { if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; - return dry_run_commit(argc, argv, prefix, &s); + return dry_run_commit(argc, argv, prefix, current_head, &s); } - index_file = prepare_index(argc, argv, prefix, 0); + index_file = prepare_index(argc, argv, prefix, current_head, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ - if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) { + if (!prepare_to_commit(index_file, prefix, + current_head, &s, &author_ident)) { rollback_index_files(); return 1; } /* Determine parents */ reflog_msg = getenv("GIT_REFLOG_ACTION"); - if (initial_commit) { + if (!current_head) { if (!reflog_msg) reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; - struct commit *commit; if (!reflog_msg) reflog_msg = "commit (amend)"; - commit = lookup_commit(head_sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - - for (c = commit->parents; c; c = c->next) + for (c = current_head->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (whence == FROM_MERGE) { struct strbuf m = STRBUF_INIT; @@ -1437,7 +1437,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!reflog_msg) reflog_msg = "commit (merge)"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die_errno(_("could not open '%s' for reading"), @@ -1463,7 +1463,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) reflog_msg = (whence == FROM_CHERRY_PICK) ? "commit (cherry-pick)" : "commit"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; } /* Finally, get the commit message */ @@ -1489,7 +1489,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) exit(1); } - if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1, + if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1, author_ident.buf)) { rollback_index_files(); die(_("failed to write commit object")); @@ -1497,7 +1497,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_release(&author_ident); ref_lock = lock_any_ref_for_update("HEAD", - initial_commit ? NULL : head_sha1, + !current_head + ? NULL + : current_head->object.sha1, 0); nl = strchr(sb.buf, '\n'); @@ -1512,7 +1514,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) rollback_index_files(); die(_("cannot lock HEAD ref")); } - if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) { + if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { rollback_index_files(); die(_("cannot update HEAD ref")); } @@ -1534,13 +1536,14 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct notes_rewrite_cfg *cfg; cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { - copy_note_for_rewrite(cfg, head_sha1, commit_sha1); + /* we are amending, so current_head is not NULL */ + copy_note_for_rewrite(cfg, current_head->object.sha1, sha1); finish_copy_notes_for_rewrite(cfg); } - run_rewrite_hook(head_sha1, commit_sha1); + run_rewrite_hook(current_head->object.sha1, sha1); } if (!quiet) - print_summary(prefix, commit_sha1); + print_summary(prefix, sha1, !current_head); return 0; } diff --git a/builtin/describe.c b/builtin/describe.c index 66fc291c8a..9f63067f50 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -462,8 +462,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die(_("No names found, cannot describe anything.")); if (argc == 0) { - if (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix)) - dirty = NULL; + if (dirty) { + static struct lock_file index_lock; + int fd; + + read_cache_preload(NULL); + refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, + NULL, NULL, NULL); + fd = hold_locked_index(&index_lock, 0); + 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)) + dirty = NULL; + } describe("HEAD", 1); } else if (dirty) { die(_("--dirty is incompatible with committishes")); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 0e98bff0c4..e8a800d3ac 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -353,11 +353,13 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) } } -int report_path_error(const char *ps_matched, const char **pathspec, int prefix_len) +int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix) { /* * Make sure all pathspec matched; otherwise it is an error. */ + struct strbuf sb = STRBUF_INIT; + const char *name; int num, errors = 0; for (num = 0; pathspec[num]; num++) { int other, found_dup; @@ -382,10 +384,12 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ if (found_dup) continue; + name = quote_path_relative(pathspec[num], -1, &sb, prefix); error("pathspec '%s' did not match any file(s) known to git.", - pathspec[num] + prefix_len); + name); errors++; } + strbuf_release(&sb); return errors; } @@ -577,7 +581,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) if (ps_matched) { int bad; - bad = report_path_error(ps_matched, pathspec, prefix_len); + bad = report_path_error(ps_matched, pathspec, prefix); if (bad) fprintf(stderr, "Did you forget to 'git add'?\n"); diff --git a/builtin/remote.c b/builtin/remote.c index 05b1f5b76d..f2a9c26dc3 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1103,7 +1103,7 @@ static int show(int argc, const char **argv) url = states.remote->url; url_nr = states.remote->url_nr; } - for (i=0; i < url_nr; i++) + for (i = 0; i < url_nr; i++) printf(" Push URL: %s\n", url[i]); if (!i) printf(" Push URL: %s\n", "(no URL)"); diff --git a/builtin/revert.c b/builtin/revert.c index 1f27c63343..3117776c2c 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -258,12 +258,7 @@ static void write_message(struct strbuf *msgbuf, const char *filename) static struct tree *empty_tree(void) { - struct tree *tree = xcalloc(1, sizeof(struct tree)); - - tree->object.parsed = 1; - tree->object.type = OBJ_TREE; - pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); - return tree; + return lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN); } static NORETURN void die_dirty_index(const char *me) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 76ba1d5881..835c62ab15 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -11,7 +11,7 @@ static const char * const git_update_ref_usage[] = { int cmd_update_ref(int argc, const char **argv, const char *prefix) { - const char *refname, *oldval, *msg=NULL; + const char *refname, *oldval, *msg = NULL; unsigned char sha1[20], oldsha1[20]; int delete = 0, no_deref = 0, flags = 0; struct option options[] = { @@ -1195,7 +1195,7 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule); #define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK) /* ls-files */ -int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset); +int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix); void overlay_tree_on_cache(const char *tree_name, const char *prefix); char *alias_lookup(const char *alias); @@ -515,7 +515,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) commit = work_item->item; for (parents = commit->parents; parents ; parents = parents->next) { - struct commit *parent=parents->item; + struct commit *parent = parents->item; if (!parent->indegree) continue; @@ -90,11 +90,8 @@ safe_to_abort () { then return 0 fi - ( - gettext "You seem to have moved HEAD since the last 'am' failure. -Not rewinding to ORIG_HEAD" && - echo - ) >&2 + gettextln "You seem to have moved HEAD since the last 'am' failure. +Not rewinding to ORIG_HEAD" >&2 return 1 } @@ -103,9 +100,9 @@ stop_here_user_resolve () { printf '%s\n' "$resolvemsg" stop_here $1 fi - eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\". + eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\". If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"."; echo +To restore the original branch and stop patching run \"\$cmdline --abort\"." stop_here $1 } @@ -119,7 +116,7 @@ go_next () { cannot_fallback () { echo "$1" - gettext "Cannot fall back to three-way merge."; echo + gettextln "Cannot fall back to three-way merge." exit 1 } @@ -619,9 +616,9 @@ do go_next && continue test -s "$dotest/patch" || { - eval_gettext "Patch is empty. Was it split wrong? + eval_gettextln "Patch is empty. Was it split wrong? If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"."; echo +To restore the original branch and stop patching run \"\$cmdline --abort\"." stop_here $this } rm -f "$dotest/original-commit" "$dotest/author-script" @@ -656,7 +653,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec if test -z "$GIT_AUTHOR_EMAIL" then - gettext "Patch does not have a valid e-mail address."; echo + gettextln "Patch does not have a valid e-mail address." stop_here $this fi @@ -707,7 +704,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec action=again while test "$action" = again do - gettext "Commit Body is:"; echo + gettextln "Commit Body is:" echo "--------------------------" cat "$dotest/final-commit" echo "--------------------------" @@ -771,16 +768,16 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec # working tree. resolved= git diff-index --quiet --cached HEAD -- && { - gettext "No changes - did you forget to use 'git add'? + gettextln "No changes - did you forget to use 'git add'? If there is nothing left to stage, chances are that something else -already introduced the same changes; you might want to skip this patch."; echo +already introduced the same changes; you might want to skip this patch." stop_here_user_resolve $this } unmerged=$(git ls-files -u) if test -n "$unmerged" then - gettext "You still have unmerged paths in your index -did you forget to use 'git add'?"; echo + gettextln "You still have unmerged paths in your index +did you forget to use 'git add'?" stop_here_user_resolve $this fi apply_status=0 @@ -805,7 +802,7 @@ did you forget to use 'git add'?"; echo fi if test $apply_status != 0 then - eval_gettext 'Patch failed at $msgnum $FIRSTLINE'; echo + eval_gettextln 'Patch failed at $msgnum $FIRSTLINE' stop_here_user_resolve $this fi diff --git a/git-pull.sh b/git-pull.sh index eec3a07f0f..63da37bcc2 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -217,12 +217,9 @@ then # $orig_head commit, but we are merging into $curr_head. # First update the working tree to match $curr_head. - ( - eval_gettext "Warning: fetch updated the current branch head. + eval_gettextln "Warning: fetch updated the current branch head. Warning: fast-forwarding your working tree from -Warning: commit \$orig_head." && - echo - ) >&2 +Warning: commit \$orig_head." >&2 git update-index -q --refresh git read-tree -u -m "$orig_head" "$curr_head" || die "$(eval_gettext "Cannot fast-forward your working tree. diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh index 32ca59de82..e672366f0c 100644 --- a/git-sh-i18n.sh +++ b/git-sh-i18n.sh @@ -11,19 +11,38 @@ then printf "%s" "$1" } + gettextln() { + printf "%s\n" "$1" + } + eval_gettext () { printf "%s" "$1" | ( export PATH $(git sh-i18n--envsubst --variables "$1"); git sh-i18n--envsubst "$1" ) } + + eval_gettextln () { + printf "%s\n" "$1" | ( + export PATH $(git sh-i18n--envsubst --variables "$1"); + git sh-i18n--envsubst "$1" + ) + } else gettext () { printf "%s" "# GETTEXT POISON #" } + gettextln () { + printf "%s\n" "# GETTEXT POISON #" + } + eval_gettext () { printf "%s" "# GETTEXT POISON #" } + + eval_gettextln () { + printf "%s\n" "# GETTEXT POISON #" + } fi diff --git a/git-stash.sh b/git-stash.sh index f4e6f05ee2..31dec0abf1 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -198,8 +198,8 @@ save_stash () { # $ git stash save --blah-blah 2>&1 | head -n 2 # error: unknown option for 'stash save': --blah-blah # To provide a message, use git stash save -- '--blah-blah' - eval_gettext "$("error: unknown option for 'stash save': \$option - To provide a message, use git stash save -- '\$option'")"; echo + eval_gettextln "$("error: unknown option for 'stash save': \$option + To provide a message, use git stash save -- '\$option'")" usage ;; *) @@ -470,10 +470,7 @@ apply_stash () { status=$? if test -n "$INDEX_OPTION" then - ( - gettext "Index was not unstashed." && - echo - ) >&2 + gettextln "Index was not unstashed." >&2 fi exit $status fi diff --git a/git-submodule.sh b/git-submodule.sh index f46862f61b..814d0d914e 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -228,12 +228,9 @@ cmd_add() if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1 then - ( - eval_gettext "The following path is ignored by one of your .gitignore files: + eval_gettextln "The following path is ignored by one of your .gitignore files: \$path -Use -f if you really want to add it." && - echo - ) >&2 +Use -f if you really want to add it." >&2 exit 1 fi @@ -242,7 +239,7 @@ Use -f if you really want to add it." && then if test -d "$path"/.git -o -f "$path"/.git then - eval_gettext "Adding existing repo at '\$path' to the index"; echo + eval_gettextln "Adding existing repo at '\$path' to the index" else die "$(eval_gettext "'\$path' already exists and is not a valid git repo")" fi @@ -701,10 +698,7 @@ cmd_summary() { ;; # removed *) # unexpected type - ( - eval_gettext "unexpected mode \$mod_dst" && - echo - ) >&2 + eval_gettextln "unexpected mode \$mod_dst" >&2 continue ;; esac fi @@ -791,9 +785,9 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - gettext "# Submodules changed but not updated:"; echo + gettextln "# Submodules changed but not updated:" else - gettext "# Submodule changes to be committed:"; echo + gettextln "# Submodule changes to be committed:" fi echo "#" sed -e 's|^|# |' -e 's|^# $|#|' diff --git a/http-push.c b/http-push.c index 6e8f6d09ab..376331a76f 100644 --- a/http-push.c +++ b/http-push.c @@ -1655,7 +1655,7 @@ static int delete_remote_branch(const char *pattern, int force) return error("Remote HEAD is not a symref"); /* Remote branch must not be the remote HEAD */ - for (i=0; symref && i<MAXDEPTH; i++) { + for (i = 0; symref && i < MAXDEPTH; i++) { if (!strcmp(remote_ref->name, symref)) return error("Remote branch %s is the current HEAD", remote_ref->name); diff --git a/merge-recursive.c b/merge-recursive.c index 0cc1e6fc14..0804eb44e7 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1601,12 +1601,10 @@ int merge_recursive(struct merge_options *o, merged_common_ancestors = pop_commit(&ca); if (merged_common_ancestors == NULL) { - /* if there is no common ancestor, make an empty tree */ - struct tree *tree = xcalloc(1, sizeof(struct tree)); + /* if there is no common ancestor, use an empty tree */ + struct tree *tree; - tree->object.parsed = 1; - tree->object.type = OBJ_TREE; - pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); + tree = lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } @@ -1105,7 +1105,7 @@ int remove_note(struct notes_tree *t, const unsigned char *object_sha1) hashcpy(l.key_sha1, object_sha1); hashclr(l.val_sha1); note_tree_remove(t, t->root, 0, &l); - if (is_null_sha1(l.val_sha1)) // no note was removed + if (is_null_sha1(l.val_sha1)) /* no note was removed */ return 1; t->dirty = 1; return 0; diff --git a/parse-options-cb.c b/parse-options-cb.c new file mode 100644 index 0000000000..c248f667c1 --- /dev/null +++ b/parse-options-cb.c @@ -0,0 +1,125 @@ +#include "git-compat-util.h" +#include "parse-options.h" +#include "cache.h" +#include "commit.h" +#include "color.h" +#include "string-list.h" + +/*----- some often used options -----*/ + +int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) +{ + int v; + + if (!arg) { + v = unset ? 0 : DEFAULT_ABBREV; + } else { + v = strtol(arg, (char **)&arg, 10); + if (*arg) + return opterror(opt, "expects a numerical value", 0); + if (v && v < MINIMUM_ABBREV) + v = MINIMUM_ABBREV; + else if (v > 40) + v = 40; + } + *(int *)(opt->value) = v; + return 0; +} + +int parse_opt_approxidate_cb(const struct option *opt, const char *arg, + int unset) +{ + *(unsigned long *)(opt->value) = approxidate(arg); + return 0; +} + +int parse_opt_color_flag_cb(const struct option *opt, const char *arg, + int unset) +{ + int value; + + if (!arg) + arg = unset ? "never" : (const char *)opt->defval; + value = git_config_colorbool(NULL, arg, -1); + if (value < 0) + return opterror(opt, + "expects \"always\", \"auto\", or \"never\"", 0); + *(int *)opt->value = value; + return 0; +} + +int parse_opt_verbosity_cb(const struct option *opt, const char *arg, + int unset) +{ + int *target = opt->value; + + if (unset) + /* --no-quiet, --no-verbose */ + *target = 0; + else if (opt->short_name == 'v') { + if (*target >= 0) + (*target)++; + else + *target = 1; + } else { + if (*target <= 0) + (*target)--; + else + *target = -1; + } + return 0; +} + +int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) +{ + unsigned char sha1[20]; + struct commit *commit; + + if (!arg) + return -1; + if (get_sha1(arg, sha1)) + return error("malformed object name %s", arg); + commit = lookup_commit_reference(sha1); + if (!commit) + return error("no such commit %s", arg); + commit_list_insert(commit, opt->value); + return 0; +} + +int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) +{ + int *target = opt->value; + *target = unset ? 2 : 1; + return 0; +} + +int parse_options_concat(struct option *dst, size_t dst_size, struct option *src) +{ + int i, j; + + for (i = 0; i < dst_size; i++) + if (dst[i].type == OPTION_END) + break; + for (j = 0; i < dst_size; i++, j++) { + dst[i] = src[j]; + if (src[j].type == OPTION_END) + return 0; + } + return -1; +} + +int parse_opt_string_list(const struct option *opt, const char *arg, int unset) +{ + struct string_list *v = opt->value; + + if (unset) { + string_list_clear(v, 0); + return 0; + } + + if (!arg) + return -1; + + string_list_append(v, xstrdup(arg)); + return 0; +} diff --git a/parse-options.c b/parse-options.c index 879ea82a31..503ab5d500 100644 --- a/parse-options.c +++ b/parse-options.c @@ -3,7 +3,6 @@ #include "cache.h" #include "commit.h" #include "color.h" -#include "string-list.h" static int parse_options_usage(struct parse_opt_ctx_t *ctx, const char * const *usagestr, @@ -12,14 +11,14 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx, #define OPT_SHORT 1 #define OPT_UNSET 2 -static int optbug(const struct option *opt, const char *reason) +int optbug(const struct option *opt, const char *reason) { if (opt->long_name) return error("BUG: option '%s' %s", opt->long_name, reason); return error("BUG: switch '%c' %s", opt->short_name, reason); } -static int opterror(const struct option *opt, const char *reason, int flags) +int opterror(const struct option *opt, const char *reason, int flags) { if (flags & OPT_SHORT) return error("switch `%c' %s", opt->short_name, reason); @@ -584,123 +583,3 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx, return usage_with_options_internal(ctx, usagestr, opts, 0, err); } - -/*----- some often used options -----*/ -#include "cache.h" - -int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) -{ - int v; - - if (!arg) { - v = unset ? 0 : DEFAULT_ABBREV; - } else { - v = strtol(arg, (char **)&arg, 10); - if (*arg) - return opterror(opt, "expects a numerical value", 0); - if (v && v < MINIMUM_ABBREV) - v = MINIMUM_ABBREV; - else if (v > 40) - v = 40; - } - *(int *)(opt->value) = v; - return 0; -} - -int parse_opt_approxidate_cb(const struct option *opt, const char *arg, - int unset) -{ - *(unsigned long *)(opt->value) = approxidate(arg); - return 0; -} - -int parse_opt_color_flag_cb(const struct option *opt, const char *arg, - int unset) -{ - int value; - - if (!arg) - arg = unset ? "never" : (const char *)opt->defval; - value = git_config_colorbool(NULL, arg, -1); - if (value < 0) - return opterror(opt, - "expects \"always\", \"auto\", or \"never\"", 0); - *(int *)opt->value = value; - return 0; -} - -int parse_opt_verbosity_cb(const struct option *opt, const char *arg, - int unset) -{ - int *target = opt->value; - - if (unset) - /* --no-quiet, --no-verbose */ - *target = 0; - else if (opt->short_name == 'v') { - if (*target >= 0) - (*target)++; - else - *target = 1; - } else { - if (*target <= 0) - (*target)--; - else - *target = -1; - } - return 0; -} - -int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) -{ - unsigned char sha1[20]; - struct commit *commit; - - if (!arg) - return -1; - if (get_sha1(arg, sha1)) - return error("malformed object name %s", arg); - commit = lookup_commit_reference(sha1); - if (!commit) - return error("no such commit %s", arg); - commit_list_insert(commit, opt->value); - return 0; -} - -int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) -{ - int *target = opt->value; - *target = unset ? 2 : 1; - return 0; -} - -int parse_options_concat(struct option *dst, size_t dst_size, struct option *src) -{ - int i, j; - - for (i = 0; i < dst_size; i++) - if (dst[i].type == OPTION_END) - break; - for (j = 0; i < dst_size; i++, j++) { - dst[i] = src[j]; - if (src[j].type == OPTION_END) - return 0; - } - return -1; -} - -int parse_opt_string_list(const struct option *opt, const char *arg, int unset) -{ - struct string_list *v = opt->value; - - if (unset) { - string_list_clear(v, 0); - return 0; - } - - if (!arg) - return -1; - - string_list_append(v, xstrdup(arg)); - return 0; -} diff --git a/parse-options.h b/parse-options.h index 05eb09b878..59e0b524bd 100644 --- a/parse-options.h +++ b/parse-options.h @@ -165,6 +165,8 @@ extern NORETURN void usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options); +extern int optbug(const struct option *opt, const char *reason); +extern int opterror(const struct option *opt, const char *reason, int flags); /*----- incremental advanced APIs -----*/ enum { @@ -325,8 +325,12 @@ static const char *path_relative(const char *in, int len, if (len < 0) len = strlen(in); - if (prefix && prefix_len < 0) - prefix_len = strlen(prefix); + if (prefix_len < 0) { + if (prefix) + prefix_len = strlen(prefix); + else + prefix_len = 0; + } off = 0; i = 0; diff --git a/read-cache.c b/read-cache.c index 46a9e60708..01a0e25051 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1084,7 +1084,7 @@ static void show_file(const char * fmt, const char * name, int in_porcelain, { if (in_porcelain && *first && header_msg) { printf("%s\n", header_msg); - *first=0; + *first = 0; } printf(fmt, name); } @@ -40,34 +40,6 @@ char *prefix_path(const char *prefix, int len, const char *path) return sanitized; } -/* - * Unlike prefix_path, this should be used if the named file does - * not have to interact with index entry; i.e. name of a random file - * on the filesystem. - */ -const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) -{ - static char path[PATH_MAX]; -#ifndef WIN32 - if (!pfx_len || is_absolute_path(arg)) - return arg; - memcpy(path, pfx, pfx_len); - strcpy(path + pfx_len, arg); -#else - char *p; - /* don't add prefix to absolute paths, but still replace '\' by '/' */ - if (is_absolute_path(arg)) - pfx_len = 0; - else if (pfx_len) - memcpy(path, pfx, pfx_len); - strcpy(path + pfx_len, arg); - for (p = path + pfx_len; *p; p++) - if (*p == '\\') - *p = '/'; -#endif - return path; -} - int check_filename(const char *prefix, const char *arg) { const char *name; diff --git a/sha1_file.c b/sha1_file.c index d5616dca08..44444ae8f4 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1217,14 +1217,34 @@ static int experimental_loose_object(unsigned char *map) unsigned int word; /* - * Is it a zlib-compressed buffer? If so, the first byte - * must be 0x78 (15-bit window size, deflated), and the - * first 16-bit word is evenly divisible by 31. If so, - * we are looking at the official format, not the experimental - * one. + * We must determine if the buffer contains the standard + * zlib-deflated stream or the experimental format based + * on the in-pack object format. Compare the header byte + * for each format: + * + * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7 + * Experimental pack-based : Stttssss : ttt = 1,2,3,4 + * + * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be + * in standard loose-object format, UNLESS it is a Git-pack + * format object *exactly* 8 bytes in size when inflated. + * + * However, RFC1950 also specifies that the 1st 16-bit word + * must be divisible by 31 - this checksum tells us our buffer + * is in the standard format, giving a false positive only if + * the 1st word of the Git-pack format object happens to be + * divisible by 31, ie: + * ((byte0 * 256) + byte1) % 31 = 0 + * => 0ttt10000www1000 % 31 = 0 + * + * As it happens, this case can only arise for www=3 & ttt=1 + * - ie, a Commit object, which would have to be 8 bytes in + * size. As no Commit can be that small, we find that the + * combination of these two criteria (bitmask & checksum) + * can always correctly determine the buffer format. */ word = (map[0] << 8) + map[1]; - if (map[0] == 0x78 && !(word % 31)) + if ((map[0] & 0x8F) == 0x08 && !(word % 31)) return 0; else return 1; diff --git a/t/t1013-loose-object-format.sh b/t/t1013-loose-object-format.sh new file mode 100755 index 0000000000..0a9cedd374 --- /dev/null +++ b/t/t1013-loose-object-format.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# +# Copyright (c) 2011 Roberto Tyley +# + +test_description='Correctly identify and parse loose object headers + +There are two file formats for loose objects - the original standard +format, and the experimental format introduced with Git v1.4.3, later +deprecated with v1.5.3. Although Git no longer writes the +experimental format, objects in both formats must be read, with the +format for a given file being determined by the header. + +Detecting file format based on header is not entirely trivial, not +least because the first byte of a zlib-deflated stream will vary +depending on how much memory was allocated for the deflation window +buffer when the object was written out (for example 4KB on Android, +rather that 32KB on a normal PC). + +The loose objects used as test vectors have been generated with the +following Git versions: + +standard format: Git v1.7.4.1 +experimental format: Git v1.4.3 (legacyheaders=false) +standard format, deflated with 4KB window size: Agit/JGit on Android +' + +. ./test-lib.sh + +assert_blob_equals() { + printf "%s" "$2" >expected && + git cat-file -p "$1" >actual && + test_cmp expected actual +} + +test_expect_success setup ' + cp -R "$TEST_DIRECTORY/t1013/objects" .git/ + git --version +' + +test_expect_success 'read standard-format loose objects' ' + git cat-file tag 8d4e360d6c70fbd72411991c02a09c442cf7a9fa && + git cat-file commit 6baee0540ea990d9761a3eb9ab183003a71c3696 && + git ls-tree 7a37b887a73791d12d26c0d3e39568a8fb0fa6e8 && + assert_blob_equals "257cc5642cb1a054f08cc83f2d943e56fd3ebe99" "foo$LF" +' + +test_expect_success 'read experimental-format loose objects' ' + git cat-file tag 76e7fa9941f4d5f97f64fea65a2cba436bc79cbb && + git cat-file commit 7875c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 && + git ls-tree 95b1625de3ba8b2214d1e0d0591138aea733f64f && + assert_blob_equals "2e65efe2a145dda7ee51d1741299f848e5bf752e" "a" && + assert_blob_equals "9ae9e86b7bd6cb1472d9373702d8249973da0832" "ab" && + assert_blob_equals "85df50785d62d3b05ab03d9cbf7e4a0b49449730" "abcd" && + assert_blob_equals "1656f9233d999f61ef23ef390b9c71d75399f435" "abcdefgh" && + assert_blob_equals "1e72a6b2c4a577ab0338860fa9fe87f761fc9bbd" "abcdefghi" && + assert_blob_equals "70e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd" "abcdefghijklmnop" && + assert_blob_equals "bd15045f6ce8ff75747562173640456a394412c8" "abcdefghijklmnopqrstuvwx" +' + +test_expect_success 'read standard-format objects deflated with smaller window buffer' ' + git cat-file tag f816d5255855ac160652ee5253b06cd8ee14165a && + git cat-file tag 149cedb5c46929d18e0f118e9fa31927487af3b6 +' + +test_done diff --git a/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 b/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 Binary files differnew file mode 100644 index 0000000000..472fd1458e --- /dev/null +++ b/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 diff --git a/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 b/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 Binary files differnew file mode 100644 index 0000000000..c379d74ae2 --- /dev/null +++ b/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 diff --git a/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd b/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd Binary files differnew file mode 100644 index 0000000000..93706305bc --- /dev/null +++ b/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd diff --git a/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 b/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 Binary files differnew file mode 100644 index 0000000000..bdcf704c9e --- /dev/null +++ b/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 diff --git a/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e b/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e Binary files differnew file mode 100644 index 0000000000..ad62c43e41 --- /dev/null +++ b/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e diff --git a/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 b/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 Binary files differnew file mode 100644 index 0000000000..3d2f0337db --- /dev/null +++ b/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 diff --git a/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd b/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd Binary files differnew file mode 100644 index 0000000000..b3f71a6ee5 --- /dev/null +++ b/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd diff --git a/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb b/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb new file mode 100644 index 0000000000..af4e9a7b0c --- /dev/null +++ b/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb @@ -0,0 +1,2 @@ +x%A0@}O1{cSZ(νthZޠ?
m6di9GhبZR'QRpqL9=gsIoopeϫ_1$*SiNwpPRB +[(d-L9
\ No newline at end of file diff --git a/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 b/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 Binary files differnew file mode 100644 index 0000000000..3dd28be5c6 --- /dev/null +++ b/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 diff --git a/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 b/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 Binary files differnew file mode 100644 index 0000000000..2b97b264c3 --- /dev/null +++ b/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 diff --git a/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 b/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 Binary files differnew file mode 100644 index 0000000000..6dff746876 --- /dev/null +++ b/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 diff --git a/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa b/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa Binary files differnew file mode 100644 index 0000000000..cb41e92d07 --- /dev/null +++ b/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa diff --git a/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f b/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f Binary files differnew file mode 100644 index 0000000000..7ac46b4f70 --- /dev/null +++ b/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f diff --git a/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 b/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 Binary files differnew file mode 100644 index 0000000000..9d8316d4e5 --- /dev/null +++ b/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 diff --git a/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 b/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 Binary files differnew file mode 100644 index 0000000000..eebf23956e --- /dev/null +++ b/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 diff --git a/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files differnew file mode 100644 index 0000000000..134cf19379 --- /dev/null +++ b/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a b/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a new file mode 100644 index 0000000000..26b75aec56 --- /dev/null +++ b/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a @@ -0,0 +1 @@ +H0a{
Ie&*G^D҆wUҗS4 ,f[VAۺx6[wtGLu?@"g{+by%M
\ No newline at end of file diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index 865b8ed26d..3b1b985996 100755 --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@ -17,8 +17,6 @@ test_expect_success setup ' cp one original.one && cp dir/two original.two ' -LF=' -' test_expect_success 'update-index and ls-files' ' git update-index --add one && diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh new file mode 100755 index 0000000000..a2b63e2c10 --- /dev/null +++ b/t/t3005-ls-files-relative.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +test_description='ls-files tests with relative paths + +This test runs git ls-files with various relative path arguments. +' + +. ./test-lib.sh + +new_line=' +' +sq=\' + +test_expect_success 'prepare' ' + : >never-mind-me && + git add never-mind-me && + mkdir top && + ( + cd top && + mkdir sub && + x="x xa xbc xdef xghij xklmno" && + y=$(echo "$x" | tr x y) && + touch $x && + touch $y && + cd sub && + git add ../x* + ) +' + +test_expect_success 'ls-files with mixed levels' ' + ( + cd top/sub && + cat >expect <<-EOF && + ../../never-mind-me + ../x + EOF + git ls-files $(cat expect) >actual && + test_cmp expect actual + ) +' + +test_expect_success 'ls-files -c' ' + ( + cd top/sub && + for f in ../y* + do + echo "error: pathspec $sq$f$sq did not match any file(s) known to git." + done >expect && + echo "Did you forget to ${sq}git add${sq}?" >>expect && + ls ../x* >>expect && + test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual 2>&1 && + test_cmp expect actual + ) +' + +test_expect_success 'ls-files -o' ' + ( + cd top/sub && + for f in ../x* + do + echo "error: pathspec $sq$f$sq did not match any file(s) known to git." + done >expect && + echo "Did you forget to ${sq}git add${sq}?" >>expect && + ls ../y* >>expect && + test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual 2>&1 && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh index 9aefe3a1be..e27f39d1e5 100755 --- a/t/t3503-cherry-pick-root.sh +++ b/t/t3503-cherry-pick-root.sh @@ -16,12 +16,20 @@ test_expect_success setup ' echo second > file2 && git add file2 && test_tick && - git commit -m "second" + git commit -m "second" && + + git symbolic-ref HEAD refs/heads/third && + rm .git/index file2 && + echo third > file3 && + git add file3 && + test_tick && + git commit -m "third" ' test_expect_success 'cherry-pick a root commit' ' + git checkout second^0 && git cherry-pick master && echo first >expect && test_cmp expect file1 @@ -50,4 +58,21 @@ test_expect_success 'revert a root commit with an external strategy' ' ' +test_expect_success 'cherry-pick two root commits' ' + + echo first >expect.file1 && + echo second >expect.file2 && + echo third >expect.file3 && + + git checkout second^0 && + git cherry-pick master third && + + test_cmp expect.file1 file1 && + test_cmp expect.file2 file2 && + test_cmp expect.file3 file3 && + git rev-parse --verify HEAD^^ && + test_must_fail git rev-parse --verify HEAD^^^ + +' + test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index c06a5ee766..1f62c151b0 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -147,7 +147,7 @@ test_commit_autosquash_flags () { git commit -a -m "intermediate commit" && test_tick && echo $H $flag >>F && - git commit -a --$flag HEAD~1 $3 && + git commit -a --$flag HEAD~1 && E=$(git cat-file commit '$H-$flag' | sed -ne "s/^encoding //p") && test "z$E" = "z$H" && @@ -160,6 +160,6 @@ test_commit_autosquash_flags () { test_commit_autosquash_flags eucJP fixup -test_commit_autosquash_flags ISO-2022-JP squash '-m "squash message"' +test_commit_autosquash_flags ISO-2022-JP squash test_done diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index da82b655b3..534ee08a44 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -10,8 +10,6 @@ test_description='quoted output' FN='濱野' GN='純' HT=' ' -LF=' -' DQ='"' echo foo 2>/dev/null > "Name and an${HT}HT" diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 4048d106d4..395adfc8a9 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -10,9 +10,6 @@ Testing basic diff tool invocation . ./test-lib.sh -LF=' -' - remove_config_vars() { # Unset all config variables used by git-difftool diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index f256475020..2cb4494262 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -1882,6 +1882,53 @@ test_expect_success 'R: --import-marks-if-exists' ' test_cmp expect io.marks ' +test_expect_success 'R: feature import-marks-if-exists' ' + rm -f io.marks && + >expect && + + git fast-import --export-marks=io.marks <<-\EOF && + feature import-marks-if-exists=not_io.marks + EOF + test_cmp expect io.marks && + + blob=$(echo hi | git hash-object --stdin) && + + echo ":1 $blob" >io.marks && + echo ":1 $blob" >expect && + echo ":2 $blob" >>expect && + + git fast-import --export-marks=io.marks <<-\EOF && + feature import-marks-if-exists=io.marks + blob + mark :2 + data 3 + hi + + EOF + test_cmp expect io.marks && + + echo ":3 $blob" >>expect && + + git fast-import --import-marks=io.marks \ + --export-marks=io.marks <<-\EOF && + feature import-marks-if-exists=not_io.marks + blob + mark :3 + data 3 + hi + + EOF + test_cmp expect io.marks && + + >expect && + + git fast-import --import-marks-if-exists=not_io.marks \ + --export-marks=io.marks <<-\EOF + feature import-marks-if-exists=io.marks + EOF + test_cmp expect io.marks +' + cat >input << EOF feature import-marks=marks.out feature export-marks=marks.new diff --git a/t/test-lib.sh b/t/test-lib.sh index df25f17929..e27422217d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -92,6 +92,10 @@ _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05" # Zero SHA-1 _z40=0000000000000000000000000000000000000000 +# Line feed +LF=' +' + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... @@ -444,20 +448,26 @@ test_debug () { test "$debug" = "" || eval "$1" } +test_eval_ () { + # This is a separate function because some tests use + # "return" to end a test_expect_success block early. + eval >&3 2>&4 "$*" +} + test_run_ () { test_cleanup=: expecting_failure=$2 - eval >&3 2>&4 "$1" + test_eval_ "$1" eval_ret=$? if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure" then - eval >&3 2>&4 "$test_cleanup" + test_eval_ "$test_cleanup" fi if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then echo "" fi - return 0 + return "$eval_ret" } test_skip () { @@ -502,8 +512,7 @@ test_expect_failure () { if ! test_skip "$@" then say >&3 "checking known breakage: $2" - test_run_ "$2" expecting_failure - if [ "$?" = 0 -a "$eval_ret" = 0 ] + if test_run_ "$2" expecting_failure then test_known_broken_ok_ "$1" else @@ -521,8 +530,7 @@ test_expect_success () { if ! test_skip "$@" then say >&3 "expecting success: $2" - test_run_ "$2" - if [ "$?" = 0 -a "$eval_ret" = 0 ] + if test_run_ "$2" then test_ok_ "$1" else diff --git a/upload-pack.c b/upload-pack.c index 6420918abe..8739bfacdf 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -533,6 +533,8 @@ static void check_non_tip(void) namebuf[41] = '\n'; for (i = get_max_object_index(); 0 < i; ) { o = get_indexed_object(--i); + if (!o) + continue; if (!(o->flags & OUR_REF)) continue; memcpy(namebuf + 1, sha1_to_hex(o->sha1), 40); |