diff options
42 files changed, 474 insertions, 177 deletions
diff --git a/Documentation/RelNotes-1.6.0.4.txt b/Documentation/RelNotes-1.6.0.4.txt index fba3f30a89..d522661d31 100644 --- a/Documentation/RelNotes-1.6.0.4.txt +++ b/Documentation/RelNotes-1.6.0.4.txt @@ -30,7 +30,7 @@ Fixes since v1.6.0.3 * 'git status' incorrectly reported a submodule directory as an untracked directory. -* 'git svn' used deprecated 'git-foo' form of subcommand invocaition. +* 'git svn' used deprecated 'git-foo' form of subcommand invocation. * 'git update-ref -d' to remove a reference did not honor --no-deref option. diff --git a/Documentation/RelNotes-1.6.0.5.txt b/Documentation/RelNotes-1.6.0.5.txt new file mode 100644 index 0000000000..1dc101c6a3 --- /dev/null +++ b/Documentation/RelNotes-1.6.0.5.txt @@ -0,0 +1,43 @@ +GIT v1.6.0.5 Release Notes +========================== + +Fixes since v1.6.0.4 +-------------------- + +* 'git checkout' used to crash when your HEAD was pointing at a deleted + branch. + +* 'git checkout' from an un-checked-out state did not allow switching out + of the current branch. + +* 'git diff' always allowed GIT_EXTERNAL_DIFF and --no-ext-diff was no-op for + the command. + +* 'git fast-export' did not export all tags. + +* 'git ls-files --with-tree=<tree>' did not work with options other + than -c, most notably with -m. + +* 'git pack-objects' did not make its best effort to honor --max-pack-size + option when a single first object already busted the given limit and + placed many objects in a single pack. + +* 'git-p4' fast import frontend was too eager to trigger its keyword expansion + logic, even on a keyword-looking string that does not have closing '$' on the + same line. + +* 'git push $there' when the remote $there is defined in $GIT_DIR/branches/$there + behaves more like what cg-push from Cogito used to work. + +* 'git tag' did not complain when given mutually incompatible set of options. + +* 'make check' cannot be run without sparse; people may have meant to say + 'make test' instead, so suggest that. + +* Many unsafe call to sprintf() style varargs functions are corrected. + +* Also contains quite a few documentation updates. + +-- +O=v1.6.0.4-39-g27f6496 + diff --git a/Documentation/config.txt b/Documentation/config.txt index 87b028fbc1..113d9d1438 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -561,9 +561,6 @@ color.status.<slot>:: to red). The values of these variables may be specified as in color.branch.<slot>. -commit.template:: - Specify a file to use as the template for new commit messages. - color.ui:: When set to `always`, always use colors in all git commands which are capable of colored output. When false (or `never`), never. When @@ -571,6 +568,9 @@ color.ui:: terminal. When more specific variables of color.* are set, they always take precedence over this setting. Defaults to false. +commit.template:: + Specify a file to use as the template for new commit messages. + diff.autorefreshindex:: When using 'git-diff' to compare with work tree files, do not consider stat-only change as changed. @@ -682,18 +682,6 @@ gc.rerereunresolved:: kept for this many days when 'git-rerere gc' is run. The default is 15 days. See linkgit:git-rerere[1]. -rerere.autoupdate:: - When set to true, `git-rerere` updates the index with the - resulting contents after it cleanly resolves conflicts using - previously recorded resolution. Defaults to false. - -rerere.enabled:: - Activate recording of resolved conflicts, so that identical - conflict hunks can be resolved automatically, should they - be encountered again. linkgit:git-rerere[1] command is by - default enabled if you create `rr-cache` directory under - `$GIT_DIR`, but can be disabled by setting this option to false. - gitcvs.enabled:: Whether the CVS server interface is enabled for this repository. See linkgit:git-cvsserver[1]. @@ -852,6 +840,10 @@ i18n.logOutputEncoding:: Character encoding the commit messages are converted to when running 'git-log' and friends. +imap:: + The configuration variables in the 'imap' section are described + in linkgit:git-imap-send[1]. + instaweb.browser:: Specify the program that will be used to browse your working repository in gitweb. See linkgit:git-instaweb[1]. @@ -887,8 +879,6 @@ man.viewer:: Specify the programs that may be used to display help in the 'man' format. See linkgit:git-help[1]. -include::merge-config.txt[] - man.<tool>.cmd:: Specify the command to invoke the specified man viewer. The specified command is evaluated in shell with the man page @@ -898,6 +888,8 @@ man.<tool>.path:: Override the path for the given tool that may be used to display help in the 'man' format. See linkgit:git-help[1]. +include::merge-config.txt[] + mergetool.<tool>.path:: Override the path for the given tool. This is useful in case your tool is not in the PATH. @@ -1006,6 +998,28 @@ pull.octopus:: pull.twohead:: The default merge strategy to use when pulling a single branch. +receive.fsckObjects:: + If it is set to true, git-receive-pack will check all received + objects. It will abort in the case of a malformed object or a + broken link. The result of an abort are only dangling objects. + Defaults to false. + +receive.unpackLimit:: + If the number of objects received in a push is below this + limit then the objects will be unpacked into loose object + files. However if the number of received objects equals or + exceeds this limit then the received pack will be stored as + a pack, after adding any missing delta bases. Storing the + pack from a push can make the push operation complete faster, + especially on slow filesystems. If not set, the value of + `transfer.unpackLimit` is used instead. + +receive.denyNonFastForwards:: + If set to true, git-receive-pack will deny a ref update which is + not a fast forward. Use this to prevent such an update via a push, + even if that push is forced. This configuration variable is + set when initializing a shared repository. + remote.<name>.url:: The URL of a remote repository. See linkgit:git-fetch[1] or linkgit:git-push[1]. @@ -1055,6 +1069,18 @@ repack.usedeltabaseoffset:: "false" and repack. Access from old git versions over the native protocol are unaffected by this option. +rerere.autoupdate:: + When set to true, `git-rerere` updates the index with the + resulting contents after it cleanly resolves conflicts using + previously recorded resolution. Defaults to false. + +rerere.enabled:: + Activate recording of resolved conflicts, so that identical + conflict hunks can be resolved automatically, should they + be encountered again. linkgit:git-rerere[1] command is by + default enabled if you create `rr-cache` directory under + `$GIT_DIR`, but can be disabled by setting this option to false. + showbranch.default:: The default set of branches for linkgit:git-show-branch[1]. See linkgit:git-show-branch[1]. @@ -1091,6 +1117,11 @@ tar.umask:: archiving user's umask will be used instead. See umask(2) and linkgit:git-archive[1]. +transfer.unpackLimit:: + When `fetch.unpackLimit` or `receive.unpackLimit` are + not set, the value of this variable is used instead. + The default value is 100. + url.<base>.insteadOf:: Any URL that starts with this value will be rewritten to start, instead, with <base>. In cases where some site serves a @@ -1119,37 +1150,6 @@ user.signingkey:: unchanged to gpg's --local-user parameter, so you may specify a key using any method that gpg supports. -imap:: - The configuration variables in the 'imap' section are described - in linkgit:git-imap-send[1]. - -receive.fsckObjects:: - If it is set to true, git-receive-pack will check all received - objects. It will abort in the case of a malformed object or a - broken link. The result of an abort are only dangling objects. - Defaults to false. - -receive.unpackLimit:: - If the number of objects received in a push is below this - limit then the objects will be unpacked into loose object - files. However if the number of received objects equals or - exceeds this limit then the received pack will be stored as - a pack, after adding any missing delta bases. Storing the - pack from a push can make the push operation complete faster, - especially on slow filesystems. If not set, the value of - `transfer.unpackLimit` is used instead. - -receive.denyNonFastForwards:: - If set to true, git-receive-pack will deny a ref update which is - not a fast forward. Use this to prevent such an update via a push, - even if that push is forced. This configuration variable is - set when initializing a shared repository. - -transfer.unpackLimit:: - When `fetch.unpackLimit` or `receive.unpackLimit` are - not set, the value of this variable is used instead. - The default value is 100. - web.browser:: Specify a web browser that may be used by some commands. Currently only linkgit:git-instaweb[1] and linkgit:git-help[1] diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt index 4b3c2b0b06..043274b1b7 100644 --- a/Documentation/git-check-attr.txt +++ b/Documentation/git-check-attr.txt @@ -3,7 +3,7 @@ git-check-attr(1) NAME ---- -git-check-attr - Display gitattributes information. +git-check-attr - Display gitattributes information SYNOPSIS diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 837fb08b79..b764130d26 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -55,13 +55,12 @@ OPTIONS -n:: --no-commit:: - Usually the command automatically creates a commit with - a commit log message stating which commit was - cherry-picked. This flag applies the change necessary - to cherry-pick the named commit to your working tree - and the index, but does not make the commit. In addition, - when this option is used, your index does not have to match - the HEAD commit. The cherry-pick is done against the + Usually the command automatically creates a commit. + This flag applies the change necessary to cherry-pick + the named commit to your working tree and the index, + but does not make the commit. In addition, when this + option is used, your index does not have to match the + HEAD commit. The cherry-pick is done against the beginning state of your index. + This is useful when cherry-picking more than one commits' diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 79be4f1c00..77604d0216 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -92,7 +92,7 @@ OPTIONS -s:: --signoff:: - Add Signed-off-by line by the commiter at the end of the commit + Add Signed-off-by line by the committer at the end of the commit log message. -n:: diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt index 8c354bd470..7d4c1a7556 100644 --- a/Documentation/git-pack-objects.txt +++ b/Documentation/git-pack-objects.txt @@ -109,6 +109,11 @@ base-name:: The default is unlimited, unless the config variable `pack.packSizeLimit` is set. +--honor-pack-keep:: + This flag causes an object already in a local pack that + has a .keep file to be ignored, even if it appears in the + standard input. + --incremental:: This flag causes an object already in a pack ignored even if it appears in the standard input. @@ -116,7 +121,7 @@ base-name:: --local:: This flag is similar to `--incremental`; instead of ignoring all packed objects, it only ignores objects - that are packed and not in the local object store + that are packed and/or not in the local object store (i.e. borrowed from an alternate). --non-empty:: diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index bbe1485a97..aaa8852629 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -38,12 +38,11 @@ OPTIONS dangling. -A:: - Same as `-a`, but any unreachable objects in a previous - pack become loose, unpacked objects, instead of being - left in the old pack. Unreachable objects are never - intentionally added to a pack, even when repacking. - When used with '-d', this option - prevents unreachable objects from being immediately + Same as `-a`, unless '-d' is used. Then any unreachable + objects in a previous pack become loose, unpacked objects, + instead of being left in the old pack. Unreachable objects + are never intentionally added to a pack, even when repacking. + This option prevents unreachable objects from being immediately deleted by way of being left in the old pack and then removed. Instead, the loose unreachable objects will be pruned according to normal expiry rules diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 82d03b4ced..5d6d30f764 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -109,7 +109,7 @@ COMMANDS This works similarly to `svn update` or 'git-pull' except that it preserves linear history with 'git-rebase' instead of -'git-merge' for ease of dcommiting with 'git-svn'. +'git-merge' for ease of dcommitting with 'git-svn'. This accepts all options that 'git-svn fetch' and 'git-rebase' accept. However, '--fetch-all' only fetches from the current @@ -522,6 +522,8 @@ have each person clone that repository with 'git-clone': git remote add origin server:/pub/project git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*' git fetch +# Create a local branch from one of the branches just fetched + git checkout -b master FETCH_HEAD # Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server) git svn init http://svn.example.com/project # Pull the latest changes from Subversion diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index a417e592ac..61fc5d7be8 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -1690,8 +1690,10 @@ to follow, not easier. SEE ALSO -------- -linkgit:gittutorial[7], linkgit:gittutorial-2[7], -linkgit:everyday[7], linkgit:gitcvs-migration[7], +linkgit:gittutorial[7], +linkgit:gittutorial-2[7], +linkgit:gitcvs-migration[7], +link:everyday.html[Everyday git], link:user-manual.html[The Git User's Manual] GIT diff --git a/Documentation/gitglossary.txt b/Documentation/gitglossary.txt index 565719ed5f..d77a45aed6 100644 --- a/Documentation/gitglossary.txt +++ b/Documentation/gitglossary.txt @@ -16,8 +16,10 @@ include::glossary-content.txt[] SEE ALSO -------- -linkgit:gittutorial[7], linkgit:gittutorial-2[7], -linkgit:everyday[7], linkgit:gitcvs-migration[7], +linkgit:gittutorial[7], +linkgit:gittutorial-2[7], +linkgit:gitcvs-migration[7], +link:everyday.html[Everyday git], link:user-manual.html[The Git User's Manual] GIT diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt index 504ae8a53b..41ec7774f4 100644 --- a/Documentation/urls-remotes.txt +++ b/Documentation/urls-remotes.txt @@ -68,13 +68,22 @@ This file should have the following format: ------------ `<url>` is required; `#<head>` is optional. -When you do not provide a refspec on the command line, -git will use the following refspec, where `<head>` defaults to `master`, -and `<repository>` is the name of this file -you provided in the command line. + +Depending on the operation, git will use one of the following +refspecs, if you don't provide one on the command line. +`<branch>` is the name of this file in `$GIT_DIR/branches` and +`<head>` defaults to `master`. + +git fetch uses: + +------------ + refs/heads/<head>:refs/heads/<branch> +------------ + +git push uses: ------------ - refs/heads/<head>:<repository> + HEAD:refs/heads/<head> ------------ diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 08d1310bf5..b6533fa206 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -536,7 +536,7 @@ $ git bisect skip ------------------------------------------------- In this case, though, git may not eventually be able to tell the first -bad one between some first skipped commits and a latter bad commit. +bad one between some first skipped commits and a later bad commit. There are also ways to automate the bisecting process if you have a test script that can tell a good from a bad commit. See @@ -4560,4 +4560,3 @@ Alternates, clone -reference, etc. More on recovery from repository corruption. See: http://marc.theaimsgroup.com/?l=git&m=117263864820799&w=2 http://marc.theaimsgroup.com/?l=git&m=117147855503798&w=2 - http://marc.theaimsgroup.com/?l=git&m=117147855503798&w=2 @@ -1 +1 @@ -Documentation/RelNotes-1.6.0.4.txt
\ No newline at end of file +Documentation/RelNotes-1.6.0.5.txt
\ No newline at end of file diff --git a/builtin-checkout.c b/builtin-checkout.c index 05eee4ecc7..c107fd643a 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -269,8 +269,7 @@ static int merge_working_tree(struct checkout_opts *opts, } /* 2-way merge to the new branch */ - topts.initial_checkout = (!active_nr && - (old->commit == new->commit)); + topts.initial_checkout = is_cache_unborn(); topts.update = 1; topts.merge = 1; topts.gently = opts->merge; @@ -422,7 +421,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) describe_detached_head("Previous HEAD position was", old.commit); - if (!old.commit) { + if (!old.commit && !opts->force) { if (!opts->quiet) { fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n"); fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name); diff --git a/builtin-diff.c b/builtin-diff.c index d5fe775fc1..26cf678591 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -290,6 +290,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; + /* Default to let external be used */ + DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); + if (nongit) die("Not a git repository"); argc = setup_revisions(argc, argv, &rev, NULL); @@ -298,7 +301,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) if (diff_setup_done(&rev.diffopt) < 0) die("diff_setup_done failed"); } - DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); + DIFF_OPT_SET(&rev.diffopt, RECURSIVE); /* diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 7c93eb878d..7d5d57ad75 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -354,7 +354,7 @@ static void get_tags_and_duplicates(struct object_array *pending, case OBJ_TAG: tag = (struct tag *)e->item; while (tag && tag->object.type == OBJ_TAG) { - string_list_insert(full_name, extra_refs)->util = tag; + string_list_append(full_name, extra_refs)->util = tag; tag = (struct tag *)tag->tagged; } if (!tag) @@ -374,7 +374,7 @@ static void get_tags_and_duplicates(struct object_array *pending, } if (commit->util) /* more than one name for the same object */ - string_list_insert(full_name, extra_refs)->util = commit; + string_list_append(full_name, extra_refs)->util = commit; else commit->util = full_name; } diff --git a/builtin-gc.c b/builtin-gc.c index fac200e0b0..53a0d43b67 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -134,19 +134,9 @@ static int too_many_packs(void) prepare_packed_git(); for (cnt = 0, p = packed_git; p; p = p->next) { - char path[PATH_MAX]; - size_t len; - int keep; - if (!p->pack_local) continue; - len = strlen(p->pack_name); - if (PATH_MAX <= len + 1) - continue; /* oops, give up */ - memcpy(path, p->pack_name, len-5); - memcpy(path + len - 5, ".keep", 6); - keep = access(p->pack_name, F_OK) && (errno == ENOENT); - if (keep) + if (p->pack_keep) continue; /* * Perhaps check the size of the pack and count only diff --git a/builtin-ls-files.c b/builtin-ls-files.c index b48327db95..f72eb85475 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -227,6 +227,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) int dtype = ce_to_dtype(ce); if (excluded(dir, ce->name, &dtype) != dir->show_ignored) continue; + if (ce->ce_flags & CE_UPDATE) + continue; err = lstat(ce->name, &st); if (show_deleted && err) show_ce_entry(tag_removed, ce); @@ -329,7 +331,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) if (prefix) { static const char *(matchbuf[2]); matchbuf[0] = prefix; - matchbuf [1] = NULL; + matchbuf[1] = NULL; match = matchbuf; } else match = NULL; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index b0dddbee4f..4411a480c1 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -71,6 +71,7 @@ static int reuse_delta = 1, reuse_object = 1; static int keep_unreachable, unpack_unreachable, include_tag; static int local; static int incremental; +static int ignore_packed_keep; static int allow_ofs_delta; static const char *base_name; static int progress = 1; @@ -245,8 +246,16 @@ static unsigned long write_object(struct sha1file *f, type = entry->type; /* write limit if limited packsize and not first object */ - limit = pack_size_limit && nr_written ? - pack_size_limit - write_offset : 0; + if (!pack_size_limit || !nr_written) + limit = 0; + else if (pack_size_limit <= write_offset) + /* + * the earlier object did not fit the limit; avoid + * mistaking this with unlimited (i.e. limit = 0). + */ + limit = 1; + else + limit = pack_size_limit - write_offset; if (!entry->delta) usable_delta = 0; /* no delta */ @@ -690,6 +699,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type, return 0; } + if (!exclude && local && has_loose_object_nonlocal(sha1)) + return 0; + for (p = packed_git; p; p = p->next) { off_t offset = find_pack_entry_one(sha1, p); if (offset) { @@ -703,6 +715,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type, return 0; if (local && !p->pack_local) return 0; + if (ignore_packed_keep && p->pack_local && p->pack_keep) + return 0; } } @@ -2042,6 +2056,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) incremental = 1; continue; } + if (!strcmp("--honor-pack-keep", arg)) { + ignore_packed_keep = 1; + continue; + } if (!prefixcmp(arg, "--compression=")) { char *end; int level = strtoul(arg+14, &end, 0); diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 0706c95818..38fef34d3f 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -206,7 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) break; case 2: opts.fn = twoway_merge; - opts.initial_checkout = !active_nr; + opts.initial_checkout = is_cache_unborn(); break; case 3: default: diff --git a/builtin-tag.c b/builtin-tag.c index 843e9ac056..11b91b3c3b 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -344,7 +344,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) const char *object_ref, *tag; struct ref_lock *lock; - int annotate = 0, sign = 0, force = 0, lines = 0, + int annotate = 0, sign = 0, force = 0, lines = -1, list = 0, delete = 0, verify = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; @@ -380,9 +380,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix) } if (sign) annotate = 1; + if (argc == 0 && !(delete || verify)) + list = 1; + if ((annotate || msg.given || msgfile || force) && + (list || delete || verify)) + usage_with_options(git_tag_usage, options); + + if (list + delete + verify > 1) + usage_with_options(git_tag_usage, options); if (list) - return list_tags(argv[0], lines); + return list_tags(argv[0], lines == -1 ? 0 : lines); + if (lines != -1) + die("-n option is only allowed with -l."); if (delete) return for_each_tag_name(argv, delete_tag); if (verify) @@ -407,11 +417,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix) } } - if (argc == 0) { - if (annotate) - usage_with_options(git_tag_usage, options); - return list_tags(NULL, lines); - } tag = argv[0]; object_ref = argc == 2 ? argv[1] : "HEAD"; @@ -255,6 +255,7 @@ static inline void remove_name_hash(struct cache_entry *ce) #define read_cache() read_index(&the_index) #define read_cache_from(path) read_index_from(&the_index, (path)) +#define is_cache_unborn() is_index_unborn(&the_index) #define read_cache_unmerged() read_index_unmerged(&the_index) #define write_cache(newfd, cache, entries) write_index(&the_index, (newfd)) #define discard_cache() discard_index(&the_index) @@ -360,6 +361,7 @@ extern int init_db(const char *template_dir, unsigned int flags); /* Initialize and use the cache information */ extern int read_index(struct index_state *); extern int read_index_from(struct index_state *, const char *path); +extern int is_index_unborn(struct index_state *); extern int read_index_unmerged(struct index_state *); extern int write_index(const struct index_state *, int newfd); extern int discard_index(struct index_state *); @@ -565,6 +567,7 @@ extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int has_sha1_pack(const unsigned char *sha1, const char **ignore); extern int has_sha1_file(const unsigned char *sha1); +extern int has_loose_object_nonlocal(const unsigned char *sha1); extern int has_pack_file(const unsigned char *sha1); extern int has_pack_index(const unsigned char *sha1); @@ -671,7 +674,8 @@ extern struct packed_git { int index_version; time_t mtime; int pack_fd; - int pack_local; + unsigned pack_local:1, + pack_keep:1; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/compat/mingw.c b/compat/mingw.c index 772cad510d..45733f9e04 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -865,6 +865,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { + DWORD attrs; + /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. @@ -876,12 +878,19 @@ int mingw_rename(const char *pold, const char *pnew) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attrs = GetFileAttributes(pnew); - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + if (GetLastError() == ERROR_ACCESS_DENIED && + (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; return -1; } + if ((attrs & FILE_ATTRIBUTE_READONLY) && + SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* revert file attributes on failure */ + SetFileAttributes(pnew, attrs); + } } errno = EACCES; return -1; diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 39a1ce5a39..554a03ff4f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -650,21 +650,12 @@ _git_branch () _git_bundle () { - local mycword="$COMP_CWORD" - case "${COMP_WORDS[0]}" in - git) - local cmd="${COMP_WORDS[2]}" - mycword="$((mycword-1))" - ;; - git-bundle*) - local cmd="${COMP_WORDS[1]}" - ;; - esac - case "$mycword" in - 1) + local cmd="${COMP_WORDS[2]}" + case "$COMP_CWORD" in + 2) __gitcomp "create list-heads verify unbundle" ;; - 2) + 3) # looking for a file ;; *) @@ -812,12 +803,7 @@ _git_fetch () __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}" ;; *) - local remote - case "${COMP_WORDS[0]}" in - git-fetch) remote="${COMP_WORDS[1]}" ;; - git) remote="${COMP_WORDS[2]}" ;; - esac - __gitcomp "$(__git_refs2 "$remote")" + __gitcomp "$(__git_refs2 "${COMP_WORDS[2]}")" ;; esac fi @@ -1060,12 +1046,7 @@ _git_pull () if [ "$COMP_CWORD" = 2 ]; then __gitcomp "$(__git_remotes)" else - local remote - case "${COMP_WORDS[0]}" in - git-pull) remote="${COMP_WORDS[1]}" ;; - git) remote="${COMP_WORDS[2]}" ;; - esac - __gitcomp "$(__git_refs "$remote")" + __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" fi } @@ -1078,19 +1059,13 @@ _git_push () else case "$cur" in *:*) - local remote - case "${COMP_WORDS[0]}" in - git-push) remote="${COMP_WORDS[1]}" ;; - git) remote="${COMP_WORDS[2]}" ;; - esac - local pfx="" case "$COMP_WORDBREAKS" in *:*) : great ;; *) pfx="${cur%%:*}:" ;; esac - __gitcomp "$(__git_refs "$remote")" "$pfx" "${cur#*:}" + __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" "$pfx" "${cur#*:}" ;; +*) __gitcomp "$(__git_refs)" + "${cur#+}" @@ -1369,7 +1344,7 @@ _git_revert () return ;; esac - COMPREPLY=() + __gitcomp "$(__git_refs)" } _git_rm () @@ -1591,7 +1566,7 @@ _git_tag () -m|-F) COMPREPLY=() ;; - -*|tag|git-tag) + -*|tag) if [ $f = 1 ]; then __gitcomp "$(__git_tags)" else diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 46136d49bf..2b122d3f51 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -963,7 +963,7 @@ class P4Sync(Command): if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text) elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): - text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', text) + text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text) contents[stat['depotFile']] = text @@ -402,6 +402,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char return end - date; } +/* Have we filled in any part of the time/date yet? */ +static inline int nodate(struct tm *tm) +{ + return tm->tm_year < 0 && + tm->tm_mon < 0 && + tm->tm_mday < 0 && + !(tm->tm_hour | tm->tm_min | tm->tm_sec); +} + /* * We've seen a digit. Time? Year? Date? */ @@ -418,7 +427,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt * more than 8 digits. This is because we don't want to rule out * numbers like 20070606 as a YYYYMMDD date. */ - if (num >= 100000000) { + if (num >= 100000000 && nodate(tm)) { time_t time = num; if (gmtime_r(&time, tm)) { *tm_gmt = 1; @@ -463,6 +472,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt } /* + * Ignore lots of numerals. We took care of 4-digit years above. + * Days or months must be one or two digits. + */ + if (n > 2) + return n; + + /* * NOTE! We will give precedence to day-of-month over month or * year numbers in the 1-12 range. So 05 is always "mday 5", * unless we already have a mday.. @@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt if (num > 0 && num < 32) { tm->tm_mday = num; - } else if (num > 1900) { - tm->tm_year = num - 1900; - } else if (num > 70) { - tm->tm_year = num; } else if (num > 0 && num < 13) { tm->tm_mon = num-1; } @@ -823,7 +835,9 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) } } - *num = number; + /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */ + if (date[0] != '0' || end - date <= 2) + *num = number; return end; } diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index a2913c2a2c..75c68d948f 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -14,7 +14,7 @@ sort | while read cmd do sed -n ' - /NAME/,/git-'"$cmd"'/H + /^NAME/,/git-'"$cmd"'/H ${ x s/.*git-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/ diff --git a/git-repack.sh b/git-repack.sh index d39eb6cea6..458a497af8 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -71,19 +71,17 @@ case ",$all_into_one," in existing="$existing $e" fi done - fi - if test -z "$args" - then - args='--unpacked --incremental' - elif test -n "$unpack_unreachable" - then - args="$args $unpack_unreachable" + if test -n "$args" -a -n "$unpack_unreachable" -a \ + -n "$remove_redundant" + then + args="$args $unpack_unreachable" + fi fi ;; esac args="$args $local $quiet $no_reuse$extra" -names=$(git pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") || +names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") || exit 1 if [ -z "$names" ]; then if test -z "$quiet"; then diff --git a/git-request-pull.sh b/git-request-pull.sh index 073a314c80..a2cf5b8215 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -4,9 +4,9 @@ # This file is licensed under the GPL v2, or a later version # at the discretion of Linus Torvalds. -USAGE='<commit> <url> [<head>]' -LONG_USAGE='Summarizes the changes since <commit> to the standard output, -and includes <url> in the message generated.' +USAGE='<start> <url> [<end>]' +LONG_USAGE='Summarizes the changes between two commits to the standard output, +and includes the given URL in the generated summary.' SUBDIRECTORY_OK='Yes' OPTIONS_SPEC= . git-sh-setup diff --git a/read-cache.c b/read-cache.c index 967f483f78..525d138e90 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1239,6 +1239,11 @@ unmap: die("index file corrupt"); } +int is_index_unborn(struct index_state *istate) +{ + return (!istate->cache_nr && !istate->alloc && !istate->timestamp); +} + int discard_index(struct index_state *istate) { istate->cache_nr = 0; @@ -298,6 +298,17 @@ static void read_branches_file(struct remote *remote) } add_url_alias(remote, p); add_fetch_refspec(remote, strbuf_detach(&branch, 0)); + /* + * Cogito compatible push: push current HEAD to remote #branch + * (master if missing) + */ + strbuf_init(&branch, 0); + strbuf_addstr(&branch, "HEAD"); + if (frag) + strbuf_addf(&branch, ":refs/heads/%s", frag); + else + strbuf_addstr(&branch, ":refs/heads/master"); + add_push_refspec(remote, strbuf_detach(&branch, 0)); remote->fetch_tags = 1; /* always auto-follow */ } diff --git a/revision.c b/revision.c index 270294af83..45fd7a3660 100644 --- a/revision.c +++ b/revision.c @@ -968,7 +968,7 @@ static void add_ignore_packed(struct rev_info *revs, const char *name) int num = ++revs->num_ignore_packed; revs->ignore_packed = xrealloc(revs->ignore_packed, - sizeof(const char **) * (num + 1)); + sizeof(const char *) * (num + 1)); revs->ignore_packed[num-1] = name; revs->ignore_packed[num] = NULL; } diff --git a/sha1_file.c b/sha1_file.c index 12fc767ee5..c35469d488 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -410,23 +410,30 @@ void prepare_alt_odb(void) read_info_alternates(get_object_directory(), 0); } -static int has_loose_object(const unsigned char *sha1) +static int has_loose_object_local(const unsigned char *sha1) { char *name = sha1_file_name(sha1); - struct alternate_object_database *alt; + return !access(name, F_OK); +} - if (!access(name, F_OK)) - return 1; +int has_loose_object_nonlocal(const unsigned char *sha1) +{ + struct alternate_object_database *alt; prepare_alt_odb(); for (alt = alt_odb_list; alt; alt = alt->next) { - name = alt->name; - fill_sha1_path(name, sha1); + fill_sha1_path(alt->name, sha1); if (!access(alt->base, F_OK)) return 1; } return 0; } +static int has_loose_object(const unsigned char *sha1) +{ + return has_loose_object_local(sha1) || + has_loose_object_nonlocal(sha1); +} + static unsigned int pack_used_ctr; static unsigned int pack_mmap_calls; static unsigned int peak_pack_open_windows; @@ -828,6 +835,11 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local) return NULL; } memcpy(p->pack_name, path, path_len); + + strcpy(p->pack_name + path_len, ".keep"); + if (!access(p->pack_name, F_OK)) + p->pack_keep = 1; + strcpy(p->pack_name + path_len, ".pack"); if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) { free(p); @@ -2220,7 +2232,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename) memcpy(buffer, filename, dirlen); strcpy(buffer + dirlen, "tmp_obj_XXXXXX"); fd = mkstemp(buffer); - if (fd < 0 && dirlen) { + if (fd < 0 && dirlen && errno == ENOENT) { /* Make sure the directory exists */ memcpy(buffer, filename, dirlen); buffer[dirlen-1] = 0; @@ -2246,7 +2258,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, filename = sha1_file_name(sha1); fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename); if (fd < 0) { - if (errno == EPERM) + if (errno == EACCES) return error("insufficient permission for adding an object to repository database %s\n", get_object_directory()); else return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno)); diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 637b4e19d5..22ef7d44b0 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -43,6 +43,13 @@ test_expect_success 'GIT_EXTERNAL_DIFF environment should apply only to diff' ' ' +test_expect_success 'GIT_EXTERNAL_DIFF environment and --no-ext-diff' ' + + GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff | + grep "^diff --git a/file b/file" + +' + test_expect_success 'diff attribute' ' git config diff.parrot.command echo && @@ -68,6 +75,13 @@ test_expect_success 'diff attribute should apply only to diff' ' ' +test_expect_success 'diff attribute and --no-ext-diff' ' + + git diff --no-ext-diff | + grep "^diff --git a/file b/file" + +' + test_expect_success 'diff attribute' ' git config --unset diff.parrot.command && @@ -94,6 +108,13 @@ test_expect_success 'diff attribute should apply only to diff' ' ' +test_expect_success 'diff attribute and --no-ext-diff' ' + + git diff --no-ext-diff | + grep "^diff --git a/file b/file" + +' + test_expect_success 'no diff with -diff' ' echo >.gitattributes "file -diff" && git diff | grep Binary diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 3a0ef8759c..2852a03265 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -375,4 +375,10 @@ test_expect_success 'index-pack with --strict' ' ) ' +test_expect_success 'tolerate absurdly small packsizelimit' ' + git config pack.packSizeLimit 2 && + packname_9=$(git pack-objects test-9 <obj-list) && + test $(wc -l <obj-list) = $(ls test-9-*.pack | wc -l) +' + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 598664ce7f..f9e878022a 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -494,4 +494,54 @@ test_expect_success 'allow deleting an invalid remote ref' ' ' +test_expect_success 'fetch with branches' ' + mk_empty && + git branch second $the_first_commit && + git checkout second && + echo ".." > testrepo/.git/branches/branch1 && + (cd testrepo && + git fetch branch1 && + r=$(git show-ref -s --verify refs/heads/branch1) && + test "z$r" = "z$the_commit" && + test 1 = $(git for-each-ref refs/heads | wc -l) + ) && + git checkout master +' + +test_expect_success 'fetch with branches containing #' ' + mk_empty && + echo "..#second" > testrepo/.git/branches/branch2 && + (cd testrepo && + git fetch branch2 && + r=$(git show-ref -s --verify refs/heads/branch2) && + test "z$r" = "z$the_first_commit" && + test 1 = $(git for-each-ref refs/heads | wc -l) + ) && + git checkout master +' + +test_expect_success 'push with branches' ' + mk_empty && + git checkout second && + echo "testrepo" > .git/branches/branch1 && + git push branch1 && + (cd testrepo && + r=$(git show-ref -s --verify refs/heads/master) && + test "z$r" = "z$the_first_commit" && + test 1 = $(git for-each-ref refs/heads | wc -l) + ) +' + +test_expect_success 'push with branches containing #' ' + mk_empty && + echo "testrepo#branch3" > .git/branches/branch2 && + git push branch2 && + (cd testrepo && + r=$(git show-ref -s --verify refs/heads/branch3) && + test "z$r" = "z$the_first_commit" && + test 1 = $(git for-each-ref refs/heads | wc -l) + ) && + git checkout master +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 33cde70595..c616deb0d0 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1090,4 +1090,15 @@ test_expect_success 'filename for the message is relative to cwd' ' git cat-file tag tag-from-subdir-2 | grep "in sub directory" ' +# mixing modes and options: + +test_expect_success 'mixing incompatibles modes and options is forbidden' ' + test_must_fail git tag -a + test_must_fail git tag -l -v + test_must_fail git tag -n 100 + test_must_fail git tag -l -m msg + test_must_fail git tag -l -F some file + test_must_fail git tag -v -s +' + test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh new file mode 100755 index 0000000000..3f602ea7de --- /dev/null +++ b/t/t7700-repack.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +test_description='git repack works correctly' + +. ./test-lib.sh + +test_expect_success 'objects in packs marked .keep are not repacked' ' + echo content1 > file1 && + echo content2 > file2 && + git add . && + git commit -m initial_commit && + # Create two packs + # The first pack will contain all of the objects except one + git rev-list --objects --all | grep -v file2 | + git pack-objects pack > /dev/null && + # The second pack will contain the excluded object + packsha1=$(git rev-list --objects --all | grep file2 | + git pack-objects pack) && + touch -r pack-$packsha1.pack pack-$packsha1.keep && + objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 | + sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") && + mv pack-* .git/objects/pack/ && + git repack -A -d -l && + git prune-packed && + for p in .git/objects/pack/*.idx; do + idx=$(basename $p) + test "pack-$packsha1.idx" = "$idx" && continue + if git verify-pack -v $p | egrep "^$objsha1"; then + found_duplicate_object=1 + echo "DUPLICATE OBJECT FOUND" + break + fi + done && + test -z "$found_duplicate_object" +' + +test_expect_success 'loose objects in alternate ODB are not repacked' ' + mkdir alt_objects && + echo `pwd`/alt_objects > .git/objects/info/alternates && + echo content3 > file3 && + objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) && + git add file3 && + git commit -m commit_file3 && + git repack -a -d -l && + git prune-packed && + for p in .git/objects/pack/*.idx; do + if git verify-pack -v $p | egrep "^$objsha1"; then + found_duplicate_object=1 + echo "DUPLICATE OBJECT FOUND" + break + fi + done && + test -z "$found_duplicate_object" +' + +test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' ' + mkdir alt_objects/pack + mv .git/objects/pack/* alt_objects/pack && + git repack -a && + myidx=$(ls -1 .git/objects/pack/*.idx) && + test -f "$myidx" && + for p in alt_objects/pack/*.idx; do + git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p" + done | while read sha1 rest; do + if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then + echo "Missing object in local pack: $sha1" + return 1 + fi + done +' + +test_done + diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 531dac060a..9813f113a2 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -8,7 +8,7 @@ fsha1= csha1= tsha1= -test_expect_success '-A option leaves unreachable objects unpacked' ' +test_expect_success '-A with -d option leaves unreachable objects unpacked' ' echo content > file1 && git add . && git commit -m initial_commit && @@ -58,7 +58,7 @@ compare_mtimes () ' -- "$@" } -test_expect_success 'unpacked objects receive timestamp of pack file' ' +test_expect_success '-A without -d option leaves unreachable objects packed' ' fsha1path=$(echo "$fsha1" | sed -e "s|\(..\)|\1/|") && fsha1path=".git/objects/$fsha1path" && csha1path=$(echo "$csha1" | sed -e "s|\(..\)|\1/|") && @@ -75,7 +75,19 @@ test_expect_success 'unpacked objects receive timestamp of pack file' ' git branch -D transient_branch && sleep 1 && git repack -A -l && - compare_mtimes "$packfile" "$fsha1path" "$csha1path" "$tsha1path" + test ! -f "$fsha1path" && + test ! -f "$csha1path" && + test ! -f "$tsha1path" && + git show $fsha1 && + git show $csha1 && + git show $tsha1 +' + +test_expect_success 'unpacked objects receive timestamp of pack file' ' + tmppack=".git/objects/pack/tmp_pack" && + ln "$packfile" "$tmppack" && + git repack -A -l -d && + compare_mtimes "$tmppack" "$fsha1path" "$csha1path" "$tsha1path" ' test_done diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index c19b4a2bab..638c858dc7 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -231,4 +231,12 @@ test_expect_success 'fast-export -C -C | fast-import' ' ' +test_expect_success 'fast-export | fast-import when master is tagged' ' + + git tag -m msg last && + git fast-export -C -C --signed-tags=strip --all > output && + test $(grep -c "^tag " output) = 3 + +' + test_done diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c index e87ab57c65..a43aa72cd0 100644 --- a/xdiff/xprepare.c +++ b/xdiff/xprepare.c @@ -23,10 +23,9 @@ #include "xinclude.h" - #define XDL_KPDIS_RUN 4 #define XDL_MAX_EQLIMIT 1024 - +#define XDL_SIMSCAN_WINDOW 100 typedef struct s_xdlclass { @@ -313,6 +312,18 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) { long r, rdis0, rpdis0, rdis1, rpdis1; /* + * Limits the window the is examined during the similar-lines + * scan. The loops below stops when dis[i - r] == 1 (line that + * has no match), but there are corner cases where the loop + * proceed all the way to the extremities by causing huge + * performance penalties in case of big files. + */ + if (i - s > XDL_SIMSCAN_WINDOW) + s = i - XDL_SIMSCAN_WINDOW; + if (e - i > XDL_SIMSCAN_WINDOW) + e = i + XDL_SIMSCAN_WINDOW; + + /* * Scans the lines before 'i' to find a run of lines that either * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1). * Note that we always call this function with dis[i] > 1, so the |