diff options
37 files changed, 649 insertions, 175 deletions
diff --git a/Documentation/RelNotes/2.1.1.txt b/Documentation/RelNotes/2.1.1.txt new file mode 100644 index 000000000..830fc3cc6 --- /dev/null +++ b/Documentation/RelNotes/2.1.1.txt @@ -0,0 +1,44 @@ +Git v2.1.1 Release Notes +======================== + + * Git 2.0 had a regression where "git fetch" into a shallowly + cloned repository from a repository with bitmap object index + enabled did not work correctly. This has been corrected. + + * Git 2.0 had a regression which broke (rarely used) "git diff-tree + -t". This has been corrected. + + * "git log --pretty/format=" with an empty format string did not + mean the more obvious "No output whatsoever" but "Use default + format", which was counterintuitive. Now it means "nothing shown + for the log message part". + + * "git -c section.var command" and "git -c section.var= command" + should pass the configuration differently (the former should be a + boolean true, the latter should be an empty string), but they + didn't work that way. Now it does. + + * Applying a patch not generated by Git in a subdirectory used to + check the whitespace breakage using the attributes for incorrect + paths. Also whitespace checks were performed even for paths + excluded via "git apply --exclude=<path>" mechanism. + + * "git bundle create" with date-range specification were meant to + exclude tags outside the range, but it did not work correctly. + + * "git add x" where x that used to be a directory has become a + symbolic link to a directory misbehaved. + + * The prompt script checked $GIT_DIR/ref/stash file to see if there + is a stash, which was a no-no. + + * "git checkout -m" did not switch to another branch while carrying + the local changes forward when a path was deleted from the index. + + * With sufficiently long refnames, fast-import could have overflown + an on-stack buffer. + + * After "pack-refs --prune" packed refs at the top-level, it failed + to prune them. + + * "git gc --auto" triggered from "git fetch --quiet" was not quiet. diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 2a93c645b..413855491 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] - [<upstream>] [<branch>] + [<upstream> [<branch>]] 'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>] 'git rebase' --continue | --skip | --abort | --edit-todo @@ -316,11 +316,8 @@ which makes little sense. -f:: --force-rebase:: - Force the rebase even if the current branch is a descendant - of the commit you are rebasing onto. Normally non-interactive rebase will - exit with the message "Current branch is up to date" in such a - situation. - Incompatible with the --interactive option. + Force a rebase even if the current branch is up-to-date and + the command without `--force` would return without doing anything. + You may find this (or --no-ff with an interactive rebase) helpful after reverting a topic branch merge, as this option recreates the topic branch with diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt index dc3a568ba..2a0de42a7 100644 --- a/Documentation/git-send-pack.txt +++ b/Documentation/git-send-pack.txt @@ -35,6 +35,16 @@ OPTIONS Instead of explicitly specifying which refs to update, update all heads that locally exist. +--stdin:: + Take the list of refs from stdin, one per line. If there + are refs specified on the command line in addition to this + option, then the refs from stdin are processed after those + on the command line. ++ +If '--stateless-rpc' is specified together with this option then +the list of refs must be in packet format (pkt-line). Each ref must +be in a separate packet, and the list must end with a flush packet. + --dry-run:: Do everything except actually send the updates. @@ -77,7 +87,8 @@ this flag. Without '--all' and without any '<ref>', the heads that exist both on the local side and on the remote side are updated. -When one or more '<ref>' are specified explicitly, it can be either a +When one or more '<ref>' are specified explicitly (whether on the +command line or via `--stdin`), it can be either a single pattern, or a pair of such pattern separated by a colon ":" (this means that a ref name cannot have a colon in it). A single pattern '<name>' is just a shorthand for '<name>:<name>'. diff --git a/Documentation/git.txt b/Documentation/git.txt index de7b870a3..8b2c5424c 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.1.0/git.html[documentation for release 2.1] +* link:v2.1.1/git.html[documentation for release 2.1.1] * release notes for + link:RelNotes/2.1.1.txt[2.1.1], link:RelNotes/2.1.0.txt[2.1]. * link:v2.0.4/git.html[documentation for release 2.0.4] @@ -452,6 +453,11 @@ example the following invocations are equivalent: given will override values from configuration files. The <name> is expected in the same format as listed by 'git config' (subkeys separated by dots). ++ +Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets +`foo.bar` to the boolean true value (just like `[foo]bar` would in a +config file). Including the equals but with an empty value (like `git -c +foo.bar= ...`) sets `foo.bar` to the empty string. --exec-path[=<path>]:: Path to wherever your core Git programs are installed. diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt index 18dea8d15..569c48a35 100644 --- a/Documentation/technical/pack-protocol.txt +++ b/Documentation/technical/pack-protocol.txt @@ -467,7 +467,7 @@ references. ---- update-request = *shallow command-list [pack-file] - shallow = PKT-LINE("shallow" SP obj-id) + shallow = PKT-LINE("shallow" SP obj-id LF) command-list = PKT-LINE(command NUL capability-list LF) *PKT-LINE(command LF) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index a4cdfbf7f..c76c8d6df 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.1.0 +DEF_VER=v2.1.1 LF=' ' @@ -1 +1 @@ -Documentation/RelNotes/2.1.0.txt
\ No newline at end of file +Documentation/RelNotes/2.1.1.txt
\ No newline at end of file diff --git a/builtin/apply.c b/builtin/apply.c index be2b4ce2f..6b7c76491 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1920,6 +1920,66 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch) return used; } +static void prefix_one(char **name) +{ + char *old_name = *name; + if (!old_name) + return; + *name = xstrdup(prefix_filename(prefix, prefix_length, *name)); + free(old_name); +} + +static void prefix_patch(struct patch *p) +{ + if (!prefix || p->is_toplevel_relative) + return; + prefix_one(&p->new_name); + prefix_one(&p->old_name); +} + +/* + * include/exclude + */ + +static struct string_list limit_by_name; +static int has_include; +static void add_name_limit(const char *name, int exclude) +{ + struct string_list_item *it; + + it = string_list_append(&limit_by_name, name); + it->util = exclude ? NULL : (void *) 1; +} + +static int use_patch(struct patch *p) +{ + const char *pathname = p->new_name ? p->new_name : p->old_name; + int i; + + /* Paths outside are not touched regardless of "--include" */ + if (0 < prefix_length) { + int pathlen = strlen(pathname); + if (pathlen <= prefix_length || + memcmp(prefix, pathname, prefix_length)) + return 0; + } + + /* See if it matches any of exclude/include rule */ + for (i = 0; i < limit_by_name.nr; i++) { + struct string_list_item *it = &limit_by_name.items[i]; + if (!wildmatch(it->string, pathname, 0, NULL)) + return (it->util != NULL); + } + + /* + * If we had any include, a path that does not match any rule is + * not used. Otherwise, we saw bunch of exclude rules (or none) + * and such a path is used. + */ + return !has_include; +} + + /* * Read the patch text in "buffer" that extends for "size" bytes; stop * reading after seeing a single patch (i.e. changes to a single file). @@ -1935,9 +1995,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) if (offset < 0) return offset; - patch->ws_rule = whitespace_rule(patch->new_name - ? patch->new_name - : patch->old_name); + prefix_patch(patch); + + if (!use_patch(patch)) + patch->ws_rule = 0; + else + patch->ws_rule = whitespace_rule(patch->new_name + ? patch->new_name + : patch->old_name); patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch); @@ -4127,64 +4192,6 @@ static int write_out_results(struct patch *list) static struct lock_file lock_file; -static struct string_list limit_by_name; -static int has_include; -static void add_name_limit(const char *name, int exclude) -{ - struct string_list_item *it; - - it = string_list_append(&limit_by_name, name); - it->util = exclude ? NULL : (void *) 1; -} - -static int use_patch(struct patch *p) -{ - const char *pathname = p->new_name ? p->new_name : p->old_name; - int i; - - /* Paths outside are not touched regardless of "--include" */ - if (0 < prefix_length) { - int pathlen = strlen(pathname); - if (pathlen <= prefix_length || - memcmp(prefix, pathname, prefix_length)) - return 0; - } - - /* See if it matches any of exclude/include rule */ - for (i = 0; i < limit_by_name.nr; i++) { - struct string_list_item *it = &limit_by_name.items[i]; - if (!wildmatch(it->string, pathname, 0, NULL)) - return (it->util != NULL); - } - - /* - * If we had any include, a path that does not match any rule is - * not used. Otherwise, we saw bunch of exclude rules (or none) - * and such a path is used. - */ - return !has_include; -} - - -static void prefix_one(char **name) -{ - char *old_name = *name; - if (!old_name) - return; - *name = xstrdup(prefix_filename(prefix, prefix_length, *name)); - free(old_name); -} - -static void prefix_patches(struct patch *p) -{ - if (!prefix || p->is_toplevel_relative) - return; - for ( ; p; p = p->next) { - prefix_one(&p->new_name); - prefix_one(&p->old_name); - } -} - #define INACCURATE_EOF (1<<0) #define RECOUNT (1<<1) @@ -4210,8 +4217,6 @@ static int apply_patch(int fd, const char *filename, int options) break; if (apply_in_reverse) reverse_patches(patch); - if (prefix) - prefix_patches(patch); if (use_patch(patch)) { patch_stats(patch); *listp = patch; diff --git a/builtin/fetch.c b/builtin/fetch.c index e8d0cca3e..159fb7e91 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1110,9 +1110,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) struct string_list list = STRING_LIST_INIT_NODUP; struct remote *remote; int result = 0; - static const char *argv_gc_auto[] = { - "gc", "--auto", NULL, - }; + struct argv_array argv_gc_auto = ARGV_ARRAY_INIT; packet_trace_identity("fetch"); @@ -1198,7 +1196,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) list.strdup_strings = 1; string_list_clear(&list, 0); - run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); + argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL); + if (verbosity < 0) + argv_array_push(&argv_gc_auto, "--quiet"); + run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD); + argv_array_clear(&argv_gc_auto); return result; } diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 5568a5bc3..eebf1a8fc 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -112,6 +112,10 @@ static pthread_mutex_t deepest_delta_mutex; #define deepest_delta_lock() lock_mutex(&deepest_delta_mutex) #define deepest_delta_unlock() unlock_mutex(&deepest_delta_mutex) +static pthread_mutex_t type_cas_mutex; +#define type_cas_lock() lock_mutex(&type_cas_mutex) +#define type_cas_unlock() unlock_mutex(&type_cas_mutex) + static pthread_key_t key; static inline void lock_mutex(pthread_mutex_t *mutex) @@ -135,6 +139,7 @@ static void init_thread(void) init_recursive_mutex(&read_mutex); pthread_mutex_init(&counter_mutex, NULL); pthread_mutex_init(&work_mutex, NULL); + pthread_mutex_init(&type_cas_mutex, NULL); if (show_stat) pthread_mutex_init(&deepest_delta_mutex, NULL); pthread_key_create(&key, NULL); @@ -157,6 +162,7 @@ static void cleanup_thread(void) pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&counter_mutex); pthread_mutex_destroy(&work_mutex); + pthread_mutex_destroy(&type_cas_mutex); if (show_stat) pthread_mutex_destroy(&deepest_delta_mutex); for (i = 0; i < nr_threads; i++) @@ -862,7 +868,6 @@ static void resolve_delta(struct object_entry *delta_obj, { void *base_data, *delta_data; - delta_obj->real_type = base->obj->real_type; if (show_stat) { delta_obj->delta_depth = base->obj->delta_depth + 1; deepest_delta_lock(); @@ -888,6 +893,26 @@ static void resolve_delta(struct object_entry *delta_obj, counter_unlock(); } +/* + * Standard boolean compare-and-swap: atomically check whether "*type" is + * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched + * and return false. + */ +static int compare_and_swap_type(enum object_type *type, + enum object_type want, + enum object_type set) +{ + enum object_type old; + + type_cas_lock(); + old = *type; + if (old == want) + *type = set; + type_cas_unlock(); + + return old == want; +} + static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *prev_base) { @@ -915,7 +940,10 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct object_entry *child = objects + deltas[base->ref_first].obj_no; struct base_data *result = alloc_base_data(); - assert(child->real_type == OBJ_REF_DELTA); + if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA, + base->obj->real_type)) + die("BUG: child->real_type != OBJ_REF_DELTA"); + resolve_delta(child, base, result); if (base->ref_first == base->ref_last && base->ofs_last == -1) free_base_data(base); @@ -929,6 +957,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *result = alloc_base_data(); assert(child->real_type == OBJ_OFS_DELTA); + child->real_type = base->obj->real_type; resolve_delta(child, base, result); if (base->ofs_first == base->ofs_last) free_base_data(base); diff --git a/builtin/send-pack.c b/builtin/send-pack.c index f420b7466..4b1bc0fef 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -110,6 +110,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) int flags; unsigned int reject_reasons; int progress = -1; + int from_stdin = 0; struct push_cas_option cas = {0}; argv++; @@ -169,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.stateless_rpc = 1; continue; } + if (!strcmp(arg, "--stdin")) { + from_stdin = 1; + continue; + } if (!strcmp(arg, "--helper-status")) { helper_status = 1; continue; @@ -201,6 +206,28 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) } if (!dest) usage(send_pack_usage); + + if (from_stdin) { + struct argv_array all_refspecs = ARGV_ARRAY_INIT; + + for (i = 0; i < nr_refspecs; i++) + argv_array_push(&all_refspecs, refspecs[i]); + + if (args.stateless_rpc) { + const char *buf; + while ((buf = packet_read_line(0, NULL))) + argv_array_push(&all_refspecs, buf); + } else { + struct strbuf line = STRBUF_INIT; + while (strbuf_getline(&line, stdin, '\n') != EOF) + argv_array_push(&all_refspecs, line.buf); + strbuf_release(&line); + } + + refspecs = all_refspecs.argv; + nr_refspecs = all_refspecs.argc; + } + /* * --all and --mirror are incompatible; neither makes sense * with any refspecs. @@ -221,8 +221,8 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs) line = memmem(buf, size, "\ntagger ", 8); if (!line++) return 1; - lineend = memchr(line, buf + size - line, '\n'); - line = memchr(line, lineend ? lineend - line : buf + size - line, '>'); + lineend = memchr(line, '\n', buf + size - line); + line = memchr(line, '>', lineend ? lineend - line : buf + size - line); if (!line++) return 1; date = strtoul(line, NULL, 10); diff --git a/combine-diff.c b/combine-diff.c index 60cb4f81f..91edce58e 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1407,7 +1407,8 @@ void diff_tree_combined(const unsigned char *sha1, show_log(rev); if (rev->verbose_header && opt->output_format && - opt->output_format != DIFF_FORMAT_NO_OUTPUT) + opt->output_format != DIFF_FORMAT_NO_OUTPUT && + !commit_format_is_empty(rev->commit_format)) printf("%s%c", diff_line_prefix(opt), opt->line_termination); } @@ -159,6 +159,7 @@ extern void get_commit_format(const char *arg, struct rev_info *); extern const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator); extern void userformat_find_requirements(const char *fmt, struct userformat_want *w); +extern int commit_format_is_empty(enum cmit_fmt); extern void format_commit_message(const struct commit *commit, const char *format, struct strbuf *sb, const struct pretty_print_context *context); @@ -162,19 +162,27 @@ void git_config_push_parameter(const char *text) int git_config_parse_parameter(const char *text, config_fn_t fn, void *data) { + const char *value; struct strbuf **pair; + pair = strbuf_split_str(text, '=', 2); if (!pair[0]) return error("bogus config parameter: %s", text); - if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') + + if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') { strbuf_setlen(pair[0], pair[0]->len - 1); + value = pair[1] ? pair[1]->buf : ""; + } else { + value = NULL; + } + strbuf_trim(pair[0]); if (!pair[0]->len) { strbuf_list_free(pair); return error("bogus config parameter: %s", text); } strbuf_tolower(pair[0]); - if (fn(pair[0]->buf, pair[1] ? pair[1]->buf : NULL, data) < 0) { + if (fn(pair[0]->buf, value, data) < 0) { strbuf_list_free(pair); return -1; } diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 9d684b10a..c5473dc8d 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -468,7 +468,8 @@ __git_ps1 () fi fi if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] && - [ -r "$g/refs/stash" ]; then + git rev-parse --verify --quiet refs/stash >/dev/null + then s="$" fi diff --git a/fast-import.c b/fast-import.c index d73f58cbe..a40b4ea2d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -946,10 +946,12 @@ static void unkeep_all_packs(void) static void end_packfile(void) { - struct packed_git *old_p = pack_data, *new_p; + if (!pack_data) + return; clear_delta_base_cache(); if (object_count) { + struct packed_git *new_p; unsigned char cur_pack_sha1[20]; char *idx_name; int i; @@ -991,10 +993,11 @@ static void end_packfile(void) pack_id++; } else { - close(old_p->pack_fd); - unlink_or_warn(old_p->pack_name); + close(pack_data->pack_fd); + unlink_or_warn(pack_data->pack_name); } - free(old_p); + free(pack_data); + pack_data = NULL; /* We can't carry a delta across packfiles. */ strbuf_release(&last_blob.data); @@ -1419,7 +1422,7 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b) static void store_tree(struct tree_entry *root) { - struct tree_content *t = root->tree; + struct tree_content *t; unsigned int i, j, del; struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 }; struct object_entry *le = NULL; @@ -1427,6 +1430,10 @@ static void store_tree(struct tree_entry *root) if (!is_null_sha1(root->versions[1].sha1)) return; + if (!root->tree) + load_tree(root); + t = root->tree; + for (i = 0; i < t->entry_count; i++) { if (t->entries[i]->tree) store_tree(t->entries[i]); @@ -1731,14 +1738,16 @@ static void dump_tags(void) static const char *msg = "fast-import"; struct tag *t; struct ref_lock *lock; - char ref_name[PATH_MAX]; + struct strbuf ref_name = STRBUF_INIT; for (t = first_tag; t; t = t->next_tag) { - sprintf(ref_name, "tags/%s", t->name); - lock = lock_ref_sha1(ref_name, NULL); + strbuf_reset(&ref_name); + strbuf_addf(&ref_name, "tags/%s", t->name); + lock = lock_ref_sha1(ref_name.buf, NULL); if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0) - failure |= error("Unable to update %s", ref_name); + failure |= error("Unable to update %s", ref_name.buf); } + strbuf_release(&ref_name); } static void dump_marks_helper(FILE *f, diff --git a/log-tree.c b/log-tree.c index 0c53dc11a..95e9b1da2 100644 --- a/log-tree.c +++ b/log-tree.c @@ -649,7 +649,7 @@ void show_log(struct rev_info *opt) graph_show_commit_msg(opt->graph, &msgbuf); else fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); - if (opt->use_terminator) { + if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) { if (!opt->missing_newline) graph_show_padding(opt->graph); putchar(opt->diffopt.line_termination); @@ -676,7 +676,8 @@ int log_tree_diff_flush(struct rev_info *opt) show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && - opt->commit_format != CMIT_FMT_ONELINE) { + opt->commit_format != CMIT_FMT_ONELINE && + !commit_format_is_empty(opt->commit_format)) { /* * When showing a verbose header (i.e. log message), * and not in --pretty=oneline format, we would want @@ -17,6 +17,7 @@ Members: Thomas Rast <tr@thomasrast.ch> Christian Stimming <stimming@tuhh.de> Phillip Szelat <phillip.szelat@gmail.com> Matthias Rüster <matthias.ruester@gmail.com> + Magnus Görlitz <magnus.goerlitz@googlemail.com> Language: fr (French) Repository: https://github.com/jnavila/git @@ -29,7 +29,7 @@ msgid "" "'git commit -a'." msgstr "" "Korrigieren Sie dies im Arbeitsverzeichnis, und benutzen Sie\n" -"dann 'git add/rm <Datei>' um die Auflösung entsprechend zu markieren\n" +"dann 'git add/rm <Datei>', um die Auflösung entsprechend zu markieren\n" "und zu committen, oder benutzen Sie 'git commit -a'." #: archive.c:10 @@ -619,7 +619,7 @@ msgstr "Fehler beim Erstellen des Pfades '%s'%s" #: merge-recursive.c:703 #, c-format msgid "Removing %s to make room for subdirectory\n" -msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n" +msgstr "Entferne %s, um Platz für Unterverzeichnis zu schaffen\n" #: merge-recursive.c:717 merge-recursive.c:738 msgid ": perhaps a D/F conflict?" @@ -1037,7 +1037,7 @@ msgstr[1] "Ihr Branch ist vor '%s' um %d Commits.\n" #: remote.c:1960 msgid " (use \"git push\" to publish your local commits)\n" -msgstr " (benutzen Sie \"git push\" um lokale Commits zu publizieren)\n" +msgstr " (benutzen Sie \"git push\", um lokale Commits zu publizieren)\n" #: remote.c:1963 #, c-format @@ -1052,7 +1052,7 @@ msgstr[1] "" #: remote.c:1971 msgid " (use \"git pull\" to update your local branch)\n" msgstr "" -" (benutzen Sie \"git pull\" um Ihren lokalen Branch zu aktualisieren)\n" +" (benutzen Sie \"git pull\", um Ihren lokalen Branch zu aktualisieren)\n" #: remote.c:1974 #, c-format @@ -1072,7 +1072,7 @@ msgstr[1] "" #: remote.c:1984 msgid " (use \"git pull\" to merge the remote branch into yours)\n" msgstr "" -" (benutzen Sie \"git pull\" um Ihren Branch mit dem Remote-Branch " +" (benutzen Sie \"git pull\", um Ihren Branch mit dem Remote-Branch " "zusammenzuführen)\n" #: run-command.c:80 @@ -1136,7 +1136,7 @@ msgstr "Ihre lokalen Änderungen würden von \"revert\" überschrieben werden." #: sequencer.c:233 msgid "Commit your changes or stash them to proceed." msgstr "" -"Tragen Sie Ihre Änderungen ein oder benutzen Sie \"stash\" um fortzufahren." +"Tragen Sie Ihre Änderungen ein oder benutzen Sie \"stash\", um fortzufahren." #: sequencer.c:250 msgid "Failed to lock HEAD during fast_forward_to" @@ -1488,18 +1488,18 @@ msgstr "" #: wt-status.c:183 msgid " (use \"git add <file>...\" to mark resolution)" msgstr "" -" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)" +" (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung zu markieren)" #: wt-status.c:185 wt-status.c:189 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr "" -" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung entsprechend zu " +" (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung entsprechend zu " "markieren)" #: wt-status.c:187 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr "" -" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)" +" (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung zu markieren)" #: wt-status.c:198 msgid "Changes to be committed:" @@ -1512,20 +1512,20 @@ msgstr "Änderungen, die nicht zum Commit vorgemerkt sind:" #: wt-status.c:220 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" -" (benutzen Sie \"git add <Datei>...\" um die Änderungen zum Commit " +" (benutzen Sie \"git add <Datei>...\", um die Änderungen zum Commit " "vorzumerken)" #: wt-status.c:222 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr "" -" (benutzen Sie \"git add/rm <Datei>...\" um die Änderungen zum Commit " +" (benutzen Sie \"git add/rm <Datei>...\", um die Änderungen zum Commit " "vorzumerken)" #: wt-status.c:223 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" -" (benutzen Sie \"git checkout -- <Datei>...\" um die Änderungen im " +" (benutzen Sie \"git checkout -- <Datei>...\", um die Änderungen im " "Arbeitsverzeichnis zu verwerfen)" #: wt-status.c:225 @@ -1538,7 +1538,7 @@ msgstr "" #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr "" -" (benutzen Sie \"git %s <Datei>...\" um die Änderungen zum Commit " +" (benutzen Sie \"git %s <Datei>...\", um die Änderungen zum Commit " "vorzumerken)" #: wt-status.c:252 @@ -1653,7 +1653,7 @@ msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge." #: wt-status.c:945 msgid " (use \"git commit\" to conclude merge)" -msgstr " (benutzen Sie \"git commit\" um den Merge abzuschließen)" +msgstr " (benutzen Sie \"git commit\", um den Merge abzuschließen)" #: wt-status.c:955 msgid "You are in the middle of an am session." @@ -1670,12 +1670,12 @@ msgstr "" #: wt-status.c:964 msgid " (use \"git am --skip\" to skip this patch)" -msgstr " (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)" +msgstr " (benutzen Sie \"git am --skip\", um diesen Patch auszulassen)" #: wt-status.c:966 msgid " (use \"git am --abort\" to restore the original branch)" msgstr "" -" (benutzen Sie \"git am --abort\" um den ursprünglichen Branch " +" (benutzen Sie \"git am --abort\", um den ursprünglichen Branch " "wiederherzustellen)" #: wt-status.c:1026 wt-status.c:1043 @@ -1695,12 +1695,12 @@ msgstr "" #: wt-status.c:1036 msgid " (use \"git rebase --skip\" to skip this patch)" -msgstr " (benutzen Sie \"git rebase --skip\" um diesen Patch auszulassen)" +msgstr " (benutzen Sie \"git rebase --skip\", um diesen Patch auszulassen)" #: wt-status.c:1038 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr "" -" (benutzen Sie \"git rebase --abort\" um den ursprünglichen Branch " +" (benutzen Sie \"git rebase --abort\", um den ursprünglichen Branch " "auszuchecken)" #: wt-status.c:1051 @@ -1739,7 +1739,7 @@ msgstr "Sie editieren gerade einen Commit während eines Rebase." #: wt-status.c:1075 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr "" -" (benutzen Sie \"git commit --amend\" um den aktuellen Commit nachzubessern)" +" (benutzen Sie \"git commit --amend\", um den aktuellen Commit nachzubessern)" #: wt-status.c:1077 msgid "" @@ -1767,7 +1767,7 @@ msgstr "" #: wt-status.c:1097 msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)" msgstr "" -" (benutzen Sie \"git cherry-pick --abort\" um die Cherry-Pick-Operation " +" (benutzen Sie \"git cherry-pick --abort\", um die Cherry-Pick-Operation " "abzubrechen)" #: wt-status.c:1106 @@ -1788,7 +1788,7 @@ msgstr " (alle Konflikte behoben: führen Sie \"git revert --continue\" aus)" #: wt-status.c:1116 msgid " (use \"git revert --abort\" to cancel the revert operation)" msgstr "" -" (benutzen Sie \"git revert --abort\" um die Revert-Operation abzubrechen)" +" (benutzen Sie \"git revert --abort\", um die Revert-Operation abzubrechen)" #: wt-status.c:1127 #, c-format @@ -1802,7 +1802,7 @@ msgstr "Sie sind gerade bei einer binären Suche." #: wt-status.c:1134 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr "" -" (benutzen Sie \"git bisect reset\" um zum ursprünglichen Branch " +" (benutzen Sie \"git bisect reset\", um zum ursprünglichen Branch " "zurückzukehren)" #: wt-status.c:1309 @@ -1855,7 +1855,7 @@ msgstr "Unbeobachtete Dateien nicht aufgelistet%s" #: wt-status.c:1373 msgid " (use -u option to show untracked files)" -msgstr " (benutzen Sie die Option -u um unbeobachteten Dateien anzuzeigen)" +msgstr " (benutzen Sie die Option -u, um unbeobachteten Dateien anzuzeigen)" #: wt-status.c:1379 msgid "No changes" @@ -2235,7 +2235,7 @@ msgstr[1] "" #: builtin/apply.c:2818 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" -msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden" +msgstr "Kontext reduziert zu (%ld/%ld), um Patch-Bereich bei %d anzuwenden" #: builtin/apply.c:2824 #, c-format @@ -2691,7 +2691,7 @@ msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)" #: builtin/blame.c:2514 msgid "Show author email instead of name (Default: off)" -msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)" +msgstr "Zeigt anstatt des Namens die E-Mail-Adresse des Autors (Standard: aus)" #: builtin/blame.c:2515 msgid "Ignore whitespace differences" @@ -3085,7 +3085,7 @@ msgstr "zu viele Branches für eine Umbenennen-Operation angegeben" #: builtin/branch.c:952 msgid "too many branches to set new upstream" -msgstr "zu viele Branches angegeben um Upstream-Branch zu setzen" +msgstr "zu viele Branches angegeben, um Upstream-Branch zu setzen" #: builtin/branch.c:956 #, c-format @@ -3108,7 +3108,7 @@ msgstr "Branch '%s' existiert nicht" #: builtin/branch.c:975 msgid "too many branches to unset upstream" msgstr "" -"zu viele Branches angegeben um Konfiguration zu Upstream-Branch zu entfernen" +"zu viele Branches angegeben, um Konfiguration zu Upstream-Branch zu entfernen" #: builtin/branch.c:979 msgid "could not unset upstream of HEAD when it does not point to any branch." @@ -5071,7 +5071,7 @@ msgstr "gibt für jeden Commit das gesamte Verzeichnis aus" #: builtin/fast-export.c:718 msgid "Use the done feature to terminate the stream" -msgstr "Benutzt die \"done\"-Funktion um den Strom abzuschließen" +msgstr "Benutzt die \"done\"-Funktion, um den Strom abzuschließen" #: builtin/fast-export.c:719 msgid "Skip output of blob data" @@ -5268,7 +5268,7 @@ msgid "" " 'git remote prune %s' to remove any old, conflicting branches" msgstr "" "Einige lokale Referenzen konnten nicht aktualisiert werden; versuchen Sie\n" -"'git remote prune %s' um jeden älteren, widersprüchlichen Branch zu löschen." +"'git remote prune %s', um jeden älteren, widersprüchlichen Branch zu löschen." #: builtin/fetch.c:759 #, c-format @@ -6535,7 +6535,7 @@ msgstr "zeigt Patchformat anstatt des Standards (Patch + Zusammenfassung)" #: builtin/log.c:1217 msgid "Messaging" -msgstr "Email-Einstellungen" +msgstr "E-Mail-Einstellungen" #: builtin/log.c:1218 msgid "header" @@ -6543,11 +6543,11 @@ msgstr "Header" #: builtin/log.c:1219 msgid "add email header" -msgstr "fügt Email-Header hinzu" +msgstr "fügt E-Mail-Header hinzu" #: builtin/log.c:1220 builtin/log.c:1222 msgid "email" -msgstr "Email" +msgstr "E-Mail" #: builtin/log.c:1220 msgid "add To: header" @@ -6573,7 +6573,7 @@ msgstr "message-id" #: builtin/log.c:1228 msgid "make first mail a reply to <message-id>" -msgstr "macht aus erster Email eine Antwort zu <message-id>" +msgstr "macht aus erster E-Mail eine Antwort zu <message-id>" #: builtin/log.c:1229 builtin/log.c:1232 msgid "boundary" @@ -6978,7 +6978,7 @@ msgstr "konnte nicht von '%s' lesen" #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "" -"Merge wurde nicht committet; benutzen Sie 'git commit' um den Merge " +"Merge wurde nicht committet; benutzen Sie 'git commit', um den Merge " "abzuschließen.\n" #: builtin/merge.c:809 @@ -6990,7 +6990,7 @@ msgid "" "Lines starting with '%c' will be ignored, and an empty message aborts\n" "the commit.\n" msgstr "" -"Bitte geben Sie eine Commit-Beschreibung ein um zu erklären, warum dieser\n" +"Bitte geben Sie eine Commit-Beschreibung ein, um zu erklären, warum dieser\n" "Merge erforderlich ist, insbesondere wenn es einen aktualisierten\n" "Upstream-Branch mit einem Thema-Branch zusammenführt.\n" "\n" @@ -7156,7 +7156,7 @@ msgstr "Merge mit Strategie %s fehlgeschlagen.\n" #: builtin/merge.c:1539 #, c-format msgid "Using the %s to prepare resolving by hand.\n" -msgstr "Benutzen Sie \"%s\" um die Auflösung per Hand vorzubereiten.\n" +msgstr "Benutzen Sie \"%s\", um die Auflösung per Hand vorzubereiten.\n" #: builtin/merge.c:1551 #, c-format @@ -7299,7 +7299,7 @@ msgid "Please, stage your changes to .gitmodules or stash them to proceed" msgstr "" "Bitte merken Sie Ihre Änderungen in .gitmodules zum Commit vor oder " "benutzen\n" -"Sie \"stash\" um fortzufahren." +"Sie \"stash\", um fortzufahren." #: builtin/mv.c:156 #, c-format @@ -7368,7 +7368,7 @@ msgstr "zeigt nur Namen an (keine SHA-1)" #: builtin/name-rev.c:310 msgid "only use tags to name the commits" -msgstr "verwendet nur Tags um die Commits zu benennen" +msgstr "verwendet nur Tags, um die Commits zu benennen" #: builtin/name-rev.c:312 msgid "only use refs matching <pattern>" @@ -7621,7 +7621,7 @@ msgid "" "existing notes" msgstr "" "Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s " -"gefunden. Verwenden Sie '-f' um die existierenden Notizen zu überschreiben." +"gefunden. Verwenden Sie '-f', um die existierenden Notizen zu überschreiben." #: builtin/notes.c:460 builtin/notes.c:537 #, c-format @@ -7649,7 +7649,7 @@ msgid "" "existing notes" msgstr "" "Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. " -"Verwenden Sie '-f' um die existierenden Notizen zu überschreiben." +"Verwenden Sie '-f', um die existierenden Notizen zu überschreiben." #: builtin/notes.c:543 #, c-format @@ -9359,7 +9359,7 @@ msgid "" "(use -f to force removal)" msgstr "" "\n" -"(benutzen Sie -f um die Löschung zu erzwingen)" +"(benutzen Sie -f, um die Löschung zu erzwingen)" #: builtin/rm.c:240 msgid "the following file has changes staged in the index:" @@ -9373,7 +9373,7 @@ msgid "" "(use --cached to keep the file, or -f to force removal)" msgstr "" "\n" -"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung " +"(benutzen Sie --cached, um die Datei zu behalten, oder -f, um die Entfernung " "zu erzwingen)" #: builtin/rm.c:252 @@ -9431,7 +9431,7 @@ msgstr "Unterdrückt Commit-Beschreibungen, liefert nur Anzahl der Commits" #: builtin/shortlog.c:234 msgid "Show the email address of each author" -msgstr "Zeigt die Email-Adresse von jedem Autor" +msgstr "Zeigt die E-Mail-Adresse von jedem Autor" #: builtin/shortlog.c:235 msgid "w[,i1[,i2]]" @@ -9751,7 +9751,7 @@ msgstr "annotiertes und GPG-signiertes Tag" #: builtin/tag.c:605 msgid "use another key to sign the tag" -msgstr "verwendet einen anderen Schlüssel um das Tag zu signieren" +msgstr "verwendet einen anderen Schlüssel, um das Tag zu signieren" #: builtin/tag.c:606 msgid "replace the tag if exists" @@ -10046,7 +10046,7 @@ msgid "" msgstr "" "'git help -a' und 'git help -g' listet verfügbare Unterkommandos und\n" "einige Anleitungen zu Git-Konzepten auf. Benutzen Sie 'git help <Kommando>'\n" -"oder 'git help <Konzept>' um mehr über ein spezifisches Kommando oder\n" +"oder 'git help <Konzept>', um mehr über ein spezifisches Kommando oder\n" "Konzept zu erfahren." #: parse-options.h:143 @@ -10200,7 +10200,7 @@ msgstr "" #: git-am.sh:141 msgid "Using index info to reconstruct a base tree..." msgstr "" -"Verwende Informationen aus der Staging-Area um einen Basisverzeichnis " +"Verwende Informationen aus der Staging-Area, um einen Basisverzeichnis " "nachzustellen" #: git-am.sh:156 @@ -10257,7 +10257,7 @@ msgid "" "Use \"git am --abort\" to remove it." msgstr "" "Stray $dotest Verzeichnis gefunden.\n" -"Benutzen Sie \"git am --abort\" um es zu entfernen." +"Benutzen Sie \"git am --abort\", um es zu entfernen." #: git-am.sh:535 msgid "Resolve operation not in progress, we are not resuming." @@ -10284,7 +10284,7 @@ msgstr "" #: git-am.sh:732 msgid "Patch does not have a valid e-mail address." -msgstr "Patch enthält keine gültige Email-Adresse." +msgstr "Patch enthält keine gültige E-Mail-Adresse." #: git-am.sh:779 msgid "cannot be interactive without stdin connected to a terminal." @@ -10515,7 +10515,7 @@ msgid "" msgstr "" "\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben.\n" "Bitte korrigieren Sie dies im Arbeitsverzeichnis und benutzen Sie dann \n" -"'git add/rm <Datei>' um die Auflösung entsprechend zu markieren, oder\n" +"'git add/rm <Datei>', um die Auflösung entsprechend zu markieren, oder\n" "benutzen Sie 'git commit -a'." #: git-pull.sh:25 @@ -11014,7 +11014,7 @@ msgid "" "discard them" msgstr "" "Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; " -"verwenden Sie '-f' um diese zu verwerfen" +"verwenden Sie '-f', um diese zu verwerfen" #: git-submodule.sh:701 #, sh-format @@ -24,6 +24,11 @@ static size_t commit_formats_len; static size_t commit_formats_alloc; static struct cmt_fmt_map *find_commit_format(const char *sought); +int commit_format_is_empty(enum cmit_fmt fmt) +{ + return fmt == CMIT_FMT_USERFORMAT && !*user_format; +} + static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat) { free(user_format); @@ -146,7 +151,7 @@ void get_commit_format(const char *arg, struct rev_info *rev) struct cmt_fmt_map *commit_format; rev->use_terminator = 0; - if (!arg || !*arg) { + if (!arg) { rev->commit_format = CMIT_FMT_DEFAULT; return; } @@ -155,7 +160,7 @@ void get_commit_format(const char *arg, struct rev_info *rev) return; } - if (strchr(arg, '%')) { + if (!*arg || strchr(arg, '%')) { save_user_format(rev, arg, 1); return; } diff --git a/read-cache.c b/read-cache.c index 5d3c8bd4a..6f0057fe6 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1064,6 +1064,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, return ce; } + if (has_symlink_leading_path(ce->name, ce_namelen(ce))) { + if (ignore_missing) + return ce; + if (err) + *err = ENOENT; + return NULL; + } + if (lstat(ce->name, &st) < 0) { if (ignore_missing && errno == ENOENT) return ce; @@ -2387,7 +2387,8 @@ static void try_remove_empty_parents(char *name) /* make sure nobody touched the ref, and unlink */ static void prune_ref(struct ref_to_prune *r) { - struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1); + struct ref_lock *lock = lock_any_ref_for_update(r->name, r->sha1, + 0, NULL); if (lock) { unlink_or_warn(git_path("%s", r->name)); diff --git a/remote-curl.c b/remote-curl.c index 0fcf2ce5f..558b9fecd 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -863,6 +863,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) int i, err; struct argv_array args; struct string_list_item *cas_option; + struct strbuf preamble = STRBUF_INIT; argv_array_init(&args); argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status", @@ -880,17 +881,22 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) for_each_string_list_item(cas_option, &cas_options) argv_array_push(&args, cas_option->string); argv_array_push(&args, url.buf); + + argv_array_push(&args, "--stdin"); for (i = 0; i < nr_spec; i++) - argv_array_push(&args, specs[i]); + packet_buf_write(&preamble, "%s\n", specs[i]); + packet_buf_flush(&preamble); memset(&rpc, 0, sizeof(rpc)); rpc.service_name = "git-receive-pack", rpc.argv = args.argv; + rpc.stdin_preamble = &preamble; err = rpc_service(&rpc, heads); if (rpc.result.len) write_or_die(1, rpc.result.buf, rpc.result.len); strbuf_release(&rpc.result); + strbuf_release(&preamble); argv_array_clear(&args); return err; } diff --git a/revision.c b/revision.c index 2571ada6b..615535c98 100644 --- a/revision.c +++ b/revision.c @@ -1825,7 +1825,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--pretty")) { revs->verbose_header = 1; revs->pretty_given = 1; - get_commit_format(arg+8, revs); + get_commit_format(NULL, revs); } else if (starts_with(arg, "--pretty=") || starts_with(arg, "--format=")) { /* * Detached form ("--pretty X" as opposed to "--pretty=X") diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 3f80ff0c1..46f6ae257 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -1010,6 +1010,17 @@ test_expect_success 'git -c "key=value" support' ' test_must_fail git -c name=value config core.name ' +# We just need a type-specifier here that cares about the +# distinction internally between a NULL boolean and a real +# string (because most of git's internal parsers do care). +# Using "--path" works, but we do not otherwise care about +# its semantics. +test_expect_success 'git -c can represent empty string' ' + echo >expect && + git -c foo.empty= config --path foo.empty >actual && + test_cmp expect actual +' + test_expect_success 'key sanity-checking' ' test_must_fail git config foo=bar && test_must_fail git config foo=.bar && diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index 1a2080e3d..3a017bf43 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -151,4 +151,11 @@ test_expect_success 'delete ref while another dangling packed ref' ' test_cmp /dev/null result ' +test_expect_success 'pack ref directly below refs/' ' + git update-ref refs/top HEAD && + git pack-refs --all --prune && + grep refs/top .git/packed-refs && + test_path_is_missing .git/refs/top +' + test_done diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh index c393be691..a9a058381 100755 --- a/t/t4119-apply-config.sh +++ b/t/t4119-apply-config.sh @@ -159,4 +159,21 @@ test_expect_success 'same but with traditional patch input of depth 2' ' check_result sub/file1 ' +test_expect_success 'in subdir with traditional patch input' ' + cd "$D" && + git config apply.whitespace strip && + cat >.gitattributes <<-EOF && + /* whitespace=blank-at-eol + sub/* whitespace=-blank-at-eol + EOF + rm -f sub/file1 && + cp saved sub/file1 && + git update-index --refresh && + + cd sub && + git apply ../gpatch.file && + echo "B " >expect && + test_cmp expect file1 +' + test_done diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index 5d0c59833..c6474de4c 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -512,4 +512,15 @@ test_expect_success 'whitespace=fix to expand' ' git -c core.whitespace=tab-in-indent apply --whitespace=fix patch ' +test_expect_success 'whitespace check skipped for excluded paths' ' + git config core.whitespace blank-at-eol && + >used && + >unused && + git add used unused && + echo "used" >used && + echo "unused " >unused && + git diff-files -p used unused >patch && + git apply --include=used --stat --whitespace=error <patch +' + test_done diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh new file mode 100755 index 000000000..e8737df6f --- /dev/null +++ b/t/t5408-send-pack-stdin.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +test_description='send-pack --stdin tests' +. ./test-lib.sh + +create_ref () { + tree=$(git write-tree) && + test_tick && + commit=$(echo "$1" | git commit-tree $tree) && + git update-ref "$1" $commit +} + +clear_remote () { + rm -rf remote.git && + git init --bare remote.git +} + +verify_push () { + git rev-parse "$1" >expect && + git --git-dir=remote.git rev-parse "${2:-$1}" >actual && + test_cmp expect actual +} + +test_expect_success 'setup refs' ' + cat >refs <<-\EOF && + refs/heads/A + refs/heads/C + refs/tags/D + refs/heads/B + refs/tags/E + EOF + for i in $(cat refs); do + create_ref $i || return 1 + done +' + +# sanity check our setup +test_expect_success 'refs on cmdline' ' + clear_remote && + git send-pack remote.git $(cat refs) && + for i in $(cat refs); do + verify_push $i || return 1 + done +' + +test_expect_success 'refs over stdin' ' + clear_remote && + git send-pack remote.git --stdin <refs && + for i in $(cat refs); do + verify_push $i || return 1 + done +' + +test_expect_success 'stdin lines are full refspecs' ' + clear_remote && + echo "A:other" >input && + git send-pack remote.git --stdin <input && + verify_push refs/heads/A refs/heads/other +' + +test_expect_success 'stdin mixed with cmdline' ' + clear_remote && + echo A >input && + git send-pack remote.git --stdin B <input && + verify_push A && + verify_push B +' + +test_expect_success 'cmdline refs written in order' ' + clear_remote && + test_must_fail git send-pack remote.git A:foo B:foo && + verify_push A foo +' + +test_expect_success '--stdin refs come after cmdline' ' + clear_remote && + echo A:foo >input && + test_must_fail git send-pack remote.git --stdin B:foo <input && + verify_push B foo +' + +test_expect_success 'refspecs and --mirror do not mix (cmdline)' ' + clear_remote && + test_must_fail git send-pack remote.git --mirror $(cat refs) +' + +test_expect_success 'refspecs and --mirror do not mix (stdin)' ' + clear_remote && + test_must_fail git send-pack remote.git --mirror --stdin <refs +' + +test_done diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 73af16f48..db1998873 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -323,5 +323,20 @@ test_expect_success 'push into half-auth-complete requires password' ' test_cmp expect actual ' +run_with_limited_cmdline () { + (ulimit -s 128 && "$@") +} + +test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true' + +test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' ' + sha1=$(git rev-parse HEAD) && + test_seq 2000 | + sort | + sed "s|.*|$sha1 refs/tags/really-long-tag-name-&|" \ + >.git/packed-refs && + run_with_limited_cmdline git push --mirror +' + stop_httpd test_done diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh index a45c31692..348d9b3bc 100755 --- a/t/t5704-bundle.sh +++ b/t/t5704-bundle.sh @@ -14,7 +14,10 @@ test_expect_success 'setup' ' git tag -d third ' -test_expect_success 'tags can be excluded by rev-list options' ' +test_expect_success 'annotated tags can be excluded by rev-list options' ' + git bundle create bundle --all --since=7.Apr.2005.15:14:00.-0700 && + git ls-remote bundle > output && + grep tag output && git bundle create bundle --all --since=7.Apr.2005.15:16:00.-0700 && git ls-remote bundle > output && ! grep tag output diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 0c9ec0ad4..eae9e5a93 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -223,6 +223,23 @@ test_expect_success 'checkout --merge --conflict=diff3 <branch>' ' test_cmp two expect ' +test_expect_success 'switch to another branch while carrying a deletion' ' + + git checkout -f master && git reset --hard && git clean -f && + git rm two && + + test_must_fail git checkout simple 2>errs && + test_i18ngrep overwritten errs && + + git checkout --merge simple 2>errs && + test_i18ngrep ! overwritten errs && + git ls-files -u && + test_must_fail git cat-file -t :0:two && + test "$(git cat-file -t :1:two)" = blob && + test "$(git cat-file -t :2:two)" = blob && + test_must_fail git cat-file -t :3:two +' + test_expect_success 'checkout to detach HEAD (with advice declined)' ' git config advice.detachedHead false && diff --git a/t/t7515-status-symlinks.sh b/t/t7515-status-symlinks.sh new file mode 100755 index 000000000..9f989be01 --- /dev/null +++ b/t/t7515-status-symlinks.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +test_description='git status and symlinks' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo .gitignore >.gitignore && + echo actual >>.gitignore && + echo expect >>.gitignore && + mkdir dir && + echo x >dir/file1 && + echo y >dir/file2 && + git add dir && + git commit -m initial && + git tag initial +' + +test_expect_success SYMLINKS 'symlink to a directory' ' + test_when_finished "rm symlink" && + ln -s dir symlink && + echo "?? symlink" >expect && + git status --porcelain >actual && + test_cmp expect actual +' + +test_expect_success SYMLINKS 'symlink replacing a directory' ' + test_when_finished "rm -rf copy && git reset --hard initial" && + mkdir copy && + cp dir/file1 copy/file1 && + echo "changed in copy" >copy/file2 && + git add copy && + git commit -m second && + rm -rf copy && + ln -s dir copy && + echo " D copy/file1" >expect && + echo " D copy/file2" >>expect && + echo "?? copy" >>expect && + git status --porcelain >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 5fc9ef262..d400442a4 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -3017,4 +3017,108 @@ test_expect_success 'T: empty reset doesnt delete branch' ' git rev-parse --verify refs/heads/not-to-delete ' +### +### series U (filedelete) +### + +cat >input <<INPUT_END +commit refs/heads/U +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +test setup +COMMIT +M 100644 inline hello.c +data <<BLOB +blob 1 +BLOB +M 100644 inline good/night.txt +data <<BLOB +sleep well +BLOB +M 100644 inline good/bye.txt +data <<BLOB +au revoir +BLOB + +INPUT_END + +test_expect_success 'U: initialize for U tests' ' + git fast-import <input +' + +cat >input <<INPUT_END +commit refs/heads/U +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +delete good/night.txt +COMMIT +from refs/heads/U^0 +D good/night.txt + +INPUT_END + +test_expect_success 'U: filedelete file succeeds' ' + git fast-import <input +' + +cat >expect <<EOF +:100644 000000 2907ebb4bf85d91bf0716bb3bd8a68ef48d6da76 0000000000000000000000000000000000000000 D good/night.txt +EOF + +git diff-tree -M -r U^1 U >actual + +test_expect_success 'U: validate file delete result' ' + compare_diff_raw expect actual +' + +cat >input <<INPUT_END +commit refs/heads/U +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +delete good dir +COMMIT +from refs/heads/U^0 +D good + +INPUT_END + +test_expect_success 'U: filedelete directory succeeds' ' + git fast-import <input +' + +cat >expect <<EOF +:100644 000000 69cb75792f55123d8389c156b0b41c2ff00ed507 0000000000000000000000000000000000000000 D good/bye.txt +EOF + +git diff-tree -M -r U^1 U >actual + +test_expect_success 'U: validate directory delete result' ' + compare_diff_raw expect actual +' + +cat >input <<INPUT_END +commit refs/heads/U +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +must succeed +COMMIT +from refs/heads/U^0 +D "" + +INPUT_END + +test_expect_success 'U: filedelete root succeeds' ' + git fast-import <input +' + +cat >expect <<EOF +:100644 000000 c18147dc648481eeb65dc5e66628429a64843327 0000000000000000000000000000000000000000 D hello.c +EOF + +git diff-tree -M -r U^1 U >actual + +test_expect_success 'U: validate root delete result' ' + compare_diff_raw expect actual +' + test_done diff --git a/unpack-trees.c b/unpack-trees.c index c6aa8fb99..629c658c4 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1176,7 +1176,8 @@ return_failed: static int reject_merge(const struct cache_entry *ce, struct unpack_trees_options *o) { - return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name); + return o->gently ? -1 : + add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name); } static int same(const struct cache_entry *a, const struct cache_entry *b) @@ -1631,7 +1632,7 @@ int threeway_merge(const struct cache_entry * const *stages, /* #14, #14ALT, #2ALT */ if (remote && !df_conflict_head && head_match && !remote_match) { if (index && !same(index, remote) && !same(index, head)) - return o->gently ? -1 : reject_merge(index, o); + return reject_merge(index, o); return merged_entry(remote, index, o); } /* @@ -1639,7 +1640,7 @@ int threeway_merge(const struct cache_entry * const *stages, * make sure that it matches head. */ if (index && !same(index, head)) - return o->gently ? -1 : reject_merge(index, o); + return reject_merge(index, o); if (head) { /* #5ALT, #15 */ @@ -1768,9 +1769,8 @@ int twoway_merge(const struct cache_entry * const *src, else return merged_entry(newtree, current, o); } - return o->gently ? -1 : reject_merge(current, o); - } - else if ((!oldtree && !newtree) || /* 4 and 5 */ + return reject_merge(current, o); + } else if ((!oldtree && !newtree) || /* 4 and 5 */ (!oldtree && newtree && same(current, newtree)) || /* 6 and 7 */ (oldtree && newtree && @@ -1779,26 +1779,15 @@ int twoway_merge(const struct cache_entry * const *src, !same(oldtree, newtree) && /* 18 and 19 */ same(current, newtree))) { return keep_entry(current, o); - } - else if (oldtree && !newtree && same(current, oldtree)) { + } else if (oldtree && !newtree && same(current, oldtree)) { /* 10 or 11 */ return deleted_entry(oldtree, current, o); - } - else if (oldtree && newtree && + } else if (oldtree && newtree && same(current, oldtree) && !same(current, newtree)) { /* 20 or 21 */ return merged_entry(newtree, current, o); - } - else { - /* all other failures */ - if (oldtree) - return o->gently ? -1 : reject_merge(oldtree, o); - if (current) - return o->gently ? -1 : reject_merge(current, o); - if (newtree) - return o->gently ? -1 : reject_merge(newtree, o); - return -1; - } + } else + return reject_merge(current, o); } else if (newtree) { if (oldtree && !o->initial_checkout) { diff --git a/upload-pack.c b/upload-pack.c index 01de944a0..433211a23 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -167,7 +167,9 @@ static void create_pack_file(void) if (!pollsize) break; - ret = poll(pfd, pollsize, 1000 * keepalive); + ret = poll(pfd, pollsize, + keepalive < 0 ? -1 : 1000 * keepalive); + if (ret < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", |