Merge branch 'mk/reachable-protect-detached-head' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 30 Sep 2014 05:10:04 +0000 (22:10 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Sep 2014 05:10:04 +0000 (22:10 -0700)
Reachability check (used in "git prune" and friends) did not add a
detached HEAD as a starting point to traverse objects still in use.

* mk/reachable-protect-detached-head:
reachable.c: add HEAD to reachability starting commits

37 files changed:
Documentation/RelNotes/2.1.1.txt [new file with mode: 0644]
Documentation/git-rebase.txt
Documentation/git-send-pack.txt
Documentation/git.txt
Documentation/technical/pack-protocol.txt
GIT-VERSION-GEN
RelNotes
builtin/apply.c
builtin/fetch.c
builtin/index-pack.c
builtin/send-pack.c
bundle.c
combine-diff.c
commit.h
config.c
contrib/completion/git-prompt.sh
fast-import.c
log-tree.c
po/TEAMS
po/de.po
pretty.c
read-cache.c
refs.c
remote-curl.c
revision.c
t/t1300-repo-config.sh
t/t3210-pack-refs.sh
t/t4119-apply-config.sh
t/t4124-apply-ws-rule.sh
t/t5408-send-pack-stdin.sh [new file with mode: 0755]
t/t5541-http-push-smart.sh
t/t5704-bundle.sh
t/t7201-co.sh
t/t7515-status-symlinks.sh [new file with mode: 0755]
t/t9300-fast-import.sh
unpack-trees.c
upload-pack.c
diff --git a/Documentation/RelNotes/2.1.1.txt b/Documentation/RelNotes/2.1.1.txt
new file mode 100644 (file)
index 0000000..830fc3c
--- /dev/null
@@ -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.
index 2a93c645bdb62c28ac9315659b794aa1d3932a4b..4138554912165478d182d5720d4d7b4c4ab78c05 100644 (file)
@@ -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
index dc3a568baa9c85e10bb6b53707cee9447363d0f2..2a0de42a75d482a4bbafefd19991dad25b3e67f9 100644 (file)
@@ -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>'.
index de7b870a35e63e43652be6468e6e5a17d2708a14..8b2c5424c4243f3d9cb791dcc47f3989006b688d 100644 (file)
@@ -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.
index 18dea8d15fa159b719a38588a0a346e58120ac61..569c48a352b76ab3fc0d31f21f0f1a1bd654f41d 100644 (file)
@@ -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)
index a4cdfbf7f6b547a45c9c561757c1588fe0fba369..c76c8d6dfd0226743d108f5a9327562dd8a5dc6d 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.1.0
+DEF_VER=v2.1.1
 
 LF='
 '
index bf760914010786c830233effc8b96ddacfb114fd..12cca326305836cae65aafea3e0dc824abfa932a 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -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
index be2b4ce2fd91640379b0a65d0aa90238d7edfd64..6b7c764918cff18957f67a2e345c0610e459859d 100644 (file)
@@ -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;
index e8d0cca3e4110e1ae6db82f21c899c44460cb849..159fb7e91614253cf7820b0c4cd7d07407c76762 100644 (file)
@@ -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;
 }
index 5568a5bc3b69be79f0d5fa09c694fd976c8319cc..eebf1a8fc21fd551f3917ad23ab5a45dff302f23 100644 (file)
@@ -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);
index f420b74665bcf1746e94b4cc5eb66ded0a2235ff..4b1bc0fef72c9764a4e4a43bb30f2c820d1aec34 100644 (file)
@@ -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.
index 71a21a67fa6bc5ce718dfc6593035f577b2dbc15..b708906cdbd2a14d0e5bcd1e1288c78777cf6a5e 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -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);
index 60cb4f81f9788efeff21d05d48f2183e94765385..91edce58e15b82428fcc5f3b006e23bf5380d38c 100644 (file)
@@ -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);
        }
index a8cbf52f15ff01778ba61a5a888263d424b2d8d2..aa8c3ca50af42375caf954e309d76731b4a9295e 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -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);
index 058505cb8d8d8bb531527b620125b0204732458a..6cbf701a8f3e8837dac9c308cc19a1483114879d 100644 (file)
--- a/config.c
+++ b/config.c
@@ -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;
        }
index 9d684b10a67ea663410db3ba68482c1a52bbc367..c5473dc8dba78b372fd95ef2bf5257ff5cdc3baf 100644 (file)
@@ -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
 
index d73f58cbe3fe4522fa24d47f9086d927b3296c8b..a40b4ea2d0447e5369efafa9943e1e46a28cc477 100644 (file)
@@ -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,
index 0c53dc11abf5aa10c83b35f07452f3c00a2998d4..95e9b1da259ef33a1c5bc7f7d07e853ebc5dbcec 100644 (file)
@@ -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
index 461cc14354c79da2baa0b1aa8bad0fc61812846b..a33a38e7d058823cc462e66288e6e940b5af81e5 100644 (file)
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -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
index e5d2b25f448b5b9847e9bcda5285198afa40930d..c807967cfcc4da737e8f142dab262534fb240734 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -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
index 3a1da6fd329efe1723bdb906a907ce4160c4633a..31fc76b2fde8297298a7d9ffd38ea7f00eede2fa 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -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;
        }
index 5d3c8bd4aaffda9915a3fd62d9d9800f4ac8baff..6f0057fe66a59e1239703ee4458de200304f727a 100644 (file)
@@ -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;
diff --git a/refs.c b/refs.c
index 27927f2319130cc0575817542dfd47c37cc5149b..82e5b1b14f7a6e7341dfcf8fbf61ae3982851e18 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -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));
index 0fcf2ce5ff20cc7c6f1bdf6257c94cf8fa21b35a..558b9fecdf5bca1deb2577a51b1e8473e3350911 100644 (file)
@@ -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;
 }
index 2571ada6bf66ce6e945c539be4b0123e5b9648a9..615535c98453336323a437530132f27824b51ac2 100644 (file)
@@ -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")
index 3f80ff0c14c47b87bbbecb74d1951a1abe6bc5ba..46f6ae25714d55066159d96f4a496f60a10790da 100755 (executable)
@@ -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 &&
index 1a2080e3dca272b6ed40739a7539f01f4f6ae65c..3a017bf437395526cf54403d4ea1db36a3cff0b3 100755 (executable)
@@ -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
index c393be691be42a0b0a982c07ffeee489d4075bce..a9a05838119c85bc017f1404b134d393029843b2 100755 (executable)
@@ -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
index 5d0c5983381b4072d915de0f8d75053b19172d66..c6474de4c8c30eba9b5375f6c4e176e67c1fd001 100755 (executable)
@@ -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 (executable)
index 0000000..e8737df
--- /dev/null
@@ -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
index 73af16f481836d3cbfa8a2f82c260d10a3a43c09..db1998873cee18a74d98d13963ad640bc1f8abbe 100755 (executable)
@@ -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
index a45c31692e17218988e6619742c366043e426039..348d9b3bc7ad3ea512f68b6200481c9f6b90d792 100755 (executable)
@@ -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
index 0c9ec0ad44ef4e3239e67a0c9e9ecc1340dcee8a..eae9e5a937150d60002620c8b29293f4d7ed122f 100755 (executable)
@@ -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 (executable)
index 0000000..9f989be
--- /dev/null
@@ -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
index 5fc9ef262ac1297d9442ed08208cb183ecc0e5c1..d400442a4a8891a6f20e1b764fa19488f803c9c4 100755 (executable)
@@ -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
index c6aa8fb993aa4bd92e4269d7a85c6b45fe9801e8..629c658c46a1b4f4bcd8bbe9770d7fd767ae2216 100644 (file)
@@ -1176,7 +1176,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 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) {
index 01de944a0a23f752364de51d7f5a5be6480575e8..433211a238cfee261e6e1f9e73d14df9178f004a 100644 (file)
@@ -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",