diff options
40 files changed, 661 insertions, 51 deletions
diff --git a/Documentation/RelNotes-1.6.4.1.txt b/Documentation/RelNotes-1.6.4.1.txt new file mode 100644 index 0000000000..e439e45b96 --- /dev/null +++ b/Documentation/RelNotes-1.6.4.1.txt @@ -0,0 +1,46 @@ +GIT v1.6.4.1 Release Notes +========================== + +Fixes since v1.6.4 +------------------ + + * An unquoted value in the configuration file, when it contains more than + one whitespaces in a row, got them replaced with a single space. + + * "git am" used to accept a single piece of e-mail per file (not a mbox) + as its input, but multiple input format support in v1.6.4 broke it. + Apparently many people have been depending on this feature. + + * The short help text for "git filter-branch" command was a single long + line, wrapped by terminals, and was hard to read. + + * The "recursive" strategy of "git merge" segfaulted when a merge has + more than one merge-bases, and merging of these merge-bases involves + a rename/rename or a rename/add conflict. + + * "git pull --rebase" did not use the right fork point when the + repository has already fetched from the upstream that rewinds the + branch it is based on in an earlier fetch. + + * Explain the concept of fast-forward more fully in "git push" + documentation, and hint to refer to it from an error message when the + command refuses an update to protect the user. + + * The default value for pack.deltacachesize, used by "git repack", is now + 256M, instead of unbounded. Otherwise a repack of a moderately sized + repository would needlessly eat into swap. + + * Document how "git repack" (hence "git gc") interacts with a repository + that borrows its objects from other repositories (e.g. ones created by + "git clone -s"). + + * "git show" on an annotated tag lacked a delimiting blank line between + the tag itself and the contents of the object it tags. + + * "git verify-pack -v" erroneously reported number of objects with too + deep delta depths as "chain length 0" objects. + + * Long names of authors and committers outside US-ASCII were sometimes + incorrectly shown in "gitweb". + +Other minor documentation updates are included. diff --git a/Documentation/config.txt b/Documentation/config.txt index c6f09f801a..2632c5149e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -605,7 +605,7 @@ color.interactive.<slot>:: Use customized color for 'git-add --interactive' output. `<slot>` may be `prompt`, `header`, `help` or `error`, for four distinct types of normal output from interactive - programs. The values of these variables may be specified as + commands. The values of these variables may be specified as in color.branch.<slot>. color.pager:: @@ -1113,7 +1113,7 @@ instaweb.port:: linkgit:git-instaweb[1]. interactive.singlekey:: - In interactive programs, allow the user to provide one-letter + In interactive commands, allow the user to provide one-letter input with a single key (i.e., without hitting enter). Currently this is used only by the `\--patch` mode of linkgit:git-add[1]. Note that this setting is silently @@ -1218,12 +1218,20 @@ pack.compression:: pack.deltaCacheSize:: The maximum memory in bytes used for caching deltas in - linkgit:git-pack-objects[1]. - A value of 0 means no limit. Defaults to 0. + linkgit:git-pack-objects[1] before writing them out to a pack. + This cache is used to speed up the writing object phase by not + having to recompute the final delta result once the best match + for all objects is found. Repacking large repositories on machines + which are tight with memory might be badly impacted by this though, + especially if this cache pushes the system into swapping. + A value of 0 means no limit. The smallest size of 1 byte may be + used to virtually disable this cache. Defaults to 256 MiB. pack.deltaCacheLimit:: The maximum size of a delta, that is cached in - linkgit:git-pack-objects[1]. Defaults to 1000. + linkgit:git-pack-objects[1]. This cache is used to speed up the + writing object phase by not having to recompute the final delta + result once the best match for all objects is found. Defaults to 1000. pack.threads:: Specifies the number of threads to spawn when searching for best diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index d313795fdb..ea3b1bc19f 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -1,7 +1,7 @@ -q:: --quiet:: Pass --quiet to git-fetch-pack and silence any other internally - used programs. + used git commands. -v:: --verbose:: diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index ab1943c712..e67b7e875e 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p] [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N] - [--refresh] [--ignore-errors] [--] <filepattern>... + [--refresh] [--ignore-errors] [--] [<filepattern>...] DESCRIPTION ----------- diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index b14de6c407..2c63a0fbae 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -72,8 +72,16 @@ These objects may be removed by normal git operations (such as 'git-commit') which automatically call `git gc --auto`. (See linkgit:git-gc[1].) If these objects are removed and were referenced by the cloned repository, then the cloned repository will become corrupt. - - ++ +Note that running `git repack` without the `-l` option in a repository +cloned with `-s` will copy objects from the source repository into a pack +in the cloned repository, removing the disk space savings of `clone -s`. +It is safe, however, to run `git gc`, which uses the `-l` option by +default. ++ +If you want to break the dependency of a repository cloned with `-s` on +its source repository, you can simply run `git repack -a` to copy all +objects from the source repository into a pack in the cloned repository. --reference <repository>:: If the reference repository is on the local machine diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index ab527b5b31..32ea8564a5 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -305,6 +305,16 @@ range in addition to the new branch name. The new branch name will point to the top-most revision that a 'git-rev-list' of this range will print. +If you need to add 'Acked-by' lines to, say, the last 10 commits (none +of which is a merge), use this command: + +-------------------------------------------------------- +git filter-branch --msg-filter ' + cat && + echo "Acked-by: Bugs Bunny <bunny@bugzilla.org>" +' HEAD~10..HEAD +-------------------------------------------------------- + *NOTE* the changes introduced by the commits, and which are not reverted by subsequent commits, will still be in the rewritten branch. If you want to throw out _changes_ together with the commits, you should use the diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index c04ae739ed..af68d694a0 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]... - [-m <msg>] <remote> <remote>... + [-m <msg>] <remote>... 'git merge' <msg> HEAD <remote>... DESCRIPTION diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 2653388fd8..58d2bd5d4a 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -195,6 +195,92 @@ reason:: refs, no explanation is needed. For a failed ref, the reason for failure is described. +Note about fast-forwards +------------------------ + +When an update changes a branch (or more in general, a ref) that used to +point at commit A to point at another commit B, it is called a +fast-forward update if and only if B is a descendant of A. + +In a fast-forward update from A to B, the set of commits that the original +commit A built on top of is a subset of the commits the new commit B +builds on top of. Hence, it does not lose any history. + +In contrast, a non-fast-forward update will lose history. For example, +suppose you and somebody else started at the same commit X, and you built +a history leading to commit B while the other person built a history +leading to commit A. The history looks like this: + +---------------- + + B + / + ---X---A + +---------------- + +Further suppose that the other person already pushed changes leading to A +back to the original repository you two obtained the original commit X. + +The push done by the other person updated the branch that used to point at +commit X to point at commit A. It is a fast-forward. + +But if you try to push, you will attempt to update the branch (that +now points at A) with commit B. This does _not_ fast-forward. If you did +so, the changes introduced by commit A will be lost, because everybody +will now start building on top of B. + +The command by default does not allow an update that is not a fast-forward +to prevent such loss of history. + +If you do not want to lose your work (history from X to B) nor the work by +the other person (history from X to A), you would need to first fetch the +history from the repository, create a history that contains changes done +by both parties, and push the result back. + +You can perform "git pull", resolve potential conflicts, and "git push" +the result. A "git pull" will create a merge commit C between commits A +and B. + +---------------- + + B---C + / / + ---X---A + +---------------- + +Updating A with the resulting merge commit will fast-forward and your +push will be accepted. + +Alternatively, you can rebase your change between X and B on top of A, +with "git pull --rebase", and push the result back. The rebase will +create a new commit D that builds the change between X and B on top of +A. + +---------------- + + B D + / / + ---X---A + +---------------- + +Again, updating A with this commit will fast-forward and your push will be +accepted. + +There is another common situation where you may encounter non-fast-forward +rejection when you try to push, and it is possible even when you are +pushing into a repository nobody else pushes into. After you push commit +A yourself (in the first picture in this section), replace it with "git +commit --amend" to produce commit B, and you try to push it out, because +forgot that you have pushed A out already. In such a case, and only if +you are certain that nobody in the meantime fetched your earlier commit A +(and started building on top of it), you can run "git push --force" to +overwrite it. In other words, "git push --force" is a method reserved for +a case where you do mean to lose history. + + Examples -------- diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index 9e2b4eaa38..82a3d29673 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -114,14 +114,14 @@ These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in "remotes/<name>". + -With `--dry-run` option, report what branches will be pruned, but do no +With `--dry-run` option, report what branches will be pruned, but do not actually prune them. 'update':: Fetch updates for a named set of remotes in the repository as defined by remotes.<group>. If a named group is not specified on the command line, -the configuration parameter remotes.default will get used; if +the configuration parameter remotes.default will be used; if remotes.default is not defined, all remotes which do not have the configuration parameter remote.<name>.skipDefaultUpdate set to true will be updated. (See linkgit:git-config[1]). diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index a765cfa4d2..974d9f527f 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -84,7 +84,7 @@ between the two operands. The following two commands are equivalent: $ git rev-list A...B ----------------------------------------------------------------------- -'git-rev-list' is a very essential git program, since it +'rev-list' is a very essential git command, since it provides the ability to build and traverse commit ancestry graphs. For this reason, it has a lot of different options that enables it to be used by commands as different as 'git-bisect' and diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index 210fde03a1..6392538807 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -14,9 +14,9 @@ DESCRIPTION Given one argument, reads which branch head the given symbolic ref refers to and outputs its path, relative to the `.git/` directory. Typically you would give `HEAD` as the <name> -argument to see on which branch your working tree is on. +argument to see which branch your working tree is on. -Give two arguments, create or update a symbolic ref <name> to +Given two arguments, creates or updates a symbolic ref <name> to point at the given branch <ref>. A symbolic ref is a regular file that stores a string that diff --git a/Documentation/git.txt b/Documentation/git.txt index 5fd5953e29..a9bacfbef4 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.4/git.html[documentation for release 1.6.4] +* link:v1.6.4.1/git.html[documentation for release 1.6.4.1] * release notes for + link:RelNotes-1.6.4.1.txt[1.6.4.1], link:RelNotes-1.6.4.txt[1.6.4]. * link:v1.6.3.4/git.html[documentation for release 1.6.3.4] @@ -327,7 +328,7 @@ Synching repositories include::cmds-synchingrepositories.txt[] -The following are helper programs used by the above; end users +The following are helper commands used by the above; end users typically do not use them directly. include::cmds-synchelpers.txt[] diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index aaa073efc8..1195e83b6e 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -404,7 +404,7 @@ Performing a three-way merge The attribute `merge` affects how three versions of a file is merged when a file-level merge is necessary during `git merge`, -and other programs such as `git revert` and `git cherry-pick`. +and other commands such as `git revert` and `git cherry-pick`. Set:: diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index 7ba5e589d7..b3640c4e64 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -12,7 +12,7 @@ git * DESCRIPTION ----------- -This tutorial explains how to use the "core" git programs to set up and +This tutorial explains how to use the "core" git commands to set up and work with a git repository. If you just need to use git as a revision control system you may prefer @@ -1328,7 +1328,7 @@ into it later. Obviously, this repository creation needs to be done only once. [NOTE] -'git-push' uses a pair of programs, +'git-push' uses a pair of commands, 'git-send-pack' on your local machine, and 'git-receive-pack' on the remote machine. The communication between the two over the network internally uses an SSH connection. diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 0b88a51d0b..67ebffa568 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -4131,7 +4131,7 @@ What does this mean? `git rev-list` is the original version of the revision walker, which _always_ printed a list of revisions to stdout. It is still functional, -and needs to, since most new Git programs start out as scripts using +and needs to, since most new Git commands start out as scripts using `git rev-list`. `git rev-parse` is not as important any more; it was only used to filter out diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index d8ae315140..55fc07f136 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.4 +DEF_VER=v1.6.4.1 LF=' ' @@ -1 +1 @@ -Documentation/RelNotes-1.6.4.txt
\ No newline at end of file +Documentation/RelNotes-1.6.4.1.txt
\ No newline at end of file diff --git a/builtin-apply.c b/builtin-apply.c index dc0ff5e08a..39dc96ae02 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -458,6 +458,76 @@ static int guess_p_value(const char *nameline) } /* + * Does the ---/+++ line has the POSIX timestamp after the last HT? + * GNU diff puts epoch there to signal a creation/deletion event. Is + * this such a timestamp? + */ +static int has_epoch_timestamp(const char *nameline) +{ + /* + * We are only interested in epoch timestamp; any non-zero + * fraction cannot be one, hence "(\.0+)?" in the regexp below. + * For the same reason, the date must be either 1969-12-31 or + * 1970-01-01, and the seconds part must be "00". + */ + const char stamp_regexp[] = + "^(1969-12-31|1970-01-01)" + " " + "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?" + " " + "([-+][0-2][0-9][0-5][0-9])\n"; + const char *timestamp = NULL, *cp; + static regex_t *stamp; + regmatch_t m[10]; + int zoneoffset; + int hourminute; + int status; + + for (cp = nameline; *cp != '\n'; cp++) { + if (*cp == '\t') + timestamp = cp + 1; + } + if (!timestamp) + return 0; + if (!stamp) { + stamp = xmalloc(sizeof(*stamp)); + if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) { + warning("Cannot prepare timestamp regexp %s", + stamp_regexp); + return 0; + } + } + + status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0); + if (status) { + if (status != REG_NOMATCH) + warning("regexec returned %d for input: %s", + status, timestamp); + return 0; + } + + zoneoffset = strtol(timestamp + m[3].rm_so + 1, NULL, 10); + zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100); + if (timestamp[m[3].rm_so] == '-') + zoneoffset = -zoneoffset; + + /* + * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31 + * (west of GMT) or 1970-01-01 (east of GMT) + */ + if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) || + (0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10))) + return 0; + + hourminute = (strtol(timestamp + 11, NULL, 10) * 60 + + strtol(timestamp + 14, NULL, 10) - + zoneoffset); + + return ((zoneoffset < 0 && hourminute == 1440) || + (0 <= zoneoffset && !hourminute)); +} + +/* * Get the name etc info from the ---/+++ lines of a traditional patch header * * FIXME! The end-of-filename heuristics are kind of screwy. For existing @@ -493,7 +563,17 @@ static void parse_traditional_patch(const char *first, const char *second, struc } else { name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB); name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB); - patch->old_name = patch->new_name = name; + if (has_epoch_timestamp(first)) { + patch->is_new = 1; + patch->is_delete = 0; + patch->new_name = name; + } else if (has_epoch_timestamp(second)) { + patch->is_new = 0; + patch->is_delete = 1; + patch->old_name = name; + } else { + patch->old_name = patch->new_name = name; + } } if (!name) die("unable to find filename in patch at line %d", linenr); diff --git a/builtin-log.c b/builtin-log.c index 0c2fa0ae2d..30358166e6 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -257,7 +257,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev) pp_user_info("Tagger", rev->commit_format, &out, buf, rev->date_mode, git_log_output_encoding ? git_log_output_encoding: git_commit_encoding); - printf("%s\n", out.buf); + printf("%s", out.buf); strbuf_release(&out); } @@ -329,11 +329,14 @@ int cmd_show(int argc, const char **argv, const char *prefix) case OBJ_TAG: { struct tag *t = (struct tag *)o; + if (rev.shown_one) + putchar('\n'); printf("%stag %s%s\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); ret = show_object(o->sha1, 1, &rev); + rev.shown_one = 1; if (ret) break; o = parse_object(t->tagged->sha1); @@ -345,12 +348,15 @@ int cmd_show(int argc, const char **argv, const char *prefix) break; } case OBJ_TREE: + if (rev.shown_one) + putchar('\n'); printf("%stree %s%s\n\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), name, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); read_tree_recursive((struct tree *)o, "", 0, 0, NULL, show_tree_object, NULL); + rev.shown_one = 1; break; case OBJ_COMMIT: rev.pending.nr = rev.pending.alloc = 0; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index ef4bf6bc14..9cc8a8451d 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -86,7 +86,7 @@ static int pack_compression_level = Z_DEFAULT_COMPRESSION; static int pack_compression_seen; static unsigned long delta_cache_size = 0; -static unsigned long max_delta_cache_size = 0; +static unsigned long max_delta_cache_size = 256 * 1024 * 1024; static unsigned long cache_max_small_delta_size = 1000; static unsigned long window_memory_limit = 0; diff --git a/builtin-push.c b/builtin-push.c index 1d92e22f0a..50328f4b08 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -140,6 +140,7 @@ static int do_push(const char *repo, int flags) struct transport *transport = transport_get(remote, url[i]); int err; + int nonfastforward; if (receivepack) transport_set_option(transport, TRANS_OPT_RECEIVEPACK, receivepack); @@ -148,13 +149,19 @@ static int do_push(const char *repo, int flags) if (flags & TRANSPORT_PUSH_VERBOSE) fprintf(stderr, "Pushing to %s\n", url[i]); - err = transport_push(transport, refspec_nr, refspec, flags); + err = transport_push(transport, refspec_nr, refspec, flags, + &nonfastforward); err |= transport_disconnect(transport); if (!err) continue; error("failed to push some refs to '%s'", url[i]); + if (nonfastforward) { + printf("To prevent you from losing history, non-fast-forward updates were rejected.\n" + "Merge the remote changes before pushing again.\n" + "See 'non-fast forward' section of 'git push --help' for details.\n"); + } errs++; } return !!errs; @@ -468,6 +468,9 @@ extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_obje extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); +/* "careful lstat()" */ +extern int check_path(const char *path, int len, struct stat *st); + #define REFRESH_REALLY 0x0001 /* ignore_valid */ #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ #define REFRESH_QUIET 0x0004 /* be quiet about it */ @@ -175,6 +175,19 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout return 0; } +/* + * This is like 'lstat()', except it refuses to follow symlinks + * in the path. + */ +int check_path(const char *path, int len, struct stat *st) +{ + if (has_symlink_leading_path(path, len)) { + errno = ENOENT; + return -1; + } + return lstat(path, st); +} + int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath) { static char path[PATH_MAX + 1]; @@ -188,7 +201,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t strcpy(path + len, ce->name); len += ce_namelen(ce); - |