diff options
45 files changed, 426 insertions, 97 deletions
diff --git a/Documentation/RelNotes-1.6.0.3.txt b/Documentation/RelNotes-1.6.0.3.txt index 214a400aa2..ae0577836a 100644 --- a/Documentation/RelNotes-1.6.0.3.txt +++ b/Documentation/RelNotes-1.6.0.3.txt @@ -24,6 +24,9 @@ Fixes since v1.6.0.2 * "git diff --no-index" on binary files no longer outputs a bogus "diff --git" header line. +* "git diff" hunk header patterns with multiple elements separated by LF + were not used correctly. + * Hunk headers in "git diff" default to using extended regular expressions, fixing some of the internal patterns on non-GNU platforms. @@ -31,9 +34,15 @@ Fixes since v1.6.0.2 * New config "diff.*.xfuncname" exposes extended regular expressions for user specified hunk header patterns. +* "git gc" when ejecting otherwise unreachable objects from packfiles into + loose form leaked memory. + * "git index-pack" was recently broken and mishandled objects added by thin-pack completion processing under memory pressure. +* "git index-pack" was recently broken and misbehaved when run from inside + .git/objects/pack/ directory. + * "git stash apply sash@{1}" was fixed to error out. Prior versions would have applied stash@{0} incorrectly. @@ -47,6 +56,8 @@ Fixes since v1.6.0.2 * "git remote show -v" now displays all URLs of a remote. +* "git checkout -b branch" was confused when branch already existed. + * "git checkout -q" once again suppresses the locally modified file list. * "git clone -q", "git fetch -q" asks remote side to not send @@ -104,9 +115,3 @@ Fixes since v1.6.0.2 ("git fetch") is still however supported. Many other documentation updates. - --- -exec >/var/tmp/1 -O=v1.6.0.2-95-g72d404d -echo O=$(git describe maint) -git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.0.4.txt b/Documentation/RelNotes-1.6.0.4.txt new file mode 100644 index 0000000000..4a4530b728 --- /dev/null +++ b/Documentation/RelNotes-1.6.0.4.txt @@ -0,0 +1,29 @@ +GIT v1.6.0.4 Release Notes +========================== + +Fixes since v1.6.0.3 +-------------------- + +* 'git-add -p' said "No changes" when only binary files were changed. + +* git-archive did not work correctly in bare repositories. + +* when we refuse to detect renames because there are too many new or + deleted files, we did not say how many there are. + +* 'git-push --mirror' tried and failed to push the stash; there is no + point in sending it to begin with. + +* 'git-send-email' had a small fd leak while scanning directory. + +* git-svn used deprecated 'git-foo' form of subcommand invocaition. + +* Plugged small memleaks here and there. + +* Also contains many documentation updates. + +-- +exec >/var/tmp/1 +O=v1.6.0.3-22-gc2163c6 +echo O=$(git describe maint) +git shortlog --no-merges $O..maint diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 841bead9db..c59edfa6a9 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -456,3 +456,30 @@ This should help you to submit patches inline using KMail. 5) Back in the compose window: add whatever other text you wish to the message, complete the addressing and subject fields, and press send. + + +Gmail +----- + +Submitting properly formatted patches via Gmail is simple now that +IMAP support is available. First, edit your ~/.gitconfig to specify your +account settings: + +[imap] + folder = "[Gmail]/Drafts" + host = imaps://imap.gmail.com + user = user@gmail.com + pass = p4ssw0rd + port = 993 + sslverify = false + +Next, ensure that your Gmail settings are correct. In "Settings" the +"Use Unicode (UTF-8) encoding for outgoing messages" should be checked. + +Once your commits are ready to send to the mailing list, run the following +command to send the patch emails to your Gmail Drafts folder. + + $ git format-patch -M --stdout origin/master | git imap-send + +Go to your Gmail account, open the Drafts folder, find the patch email, fill +in the To: and CC: fields and send away! diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 40d43b78ee..2da867d2f8 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -40,6 +40,26 @@ endif::doctype-manpage[] </literallayout> {title#}</example> endif::docbook-xsl-172[] + +ifdef::docbook-xsl-172[] +ifdef::doctype-manpage[] +# The following two small workarounds insert a simple paragraph after screen +[listingblock] +<example><title>{title}</title> +<screen> +| +</screen><simpara></simpara> +{title#}</example> + +[verseblock] +<formalpara{id? id="{id}"}><title>{title}</title><para> +{title%}<literallayout{id? id="{id}"}> +{title#}<literallayout> +| +</literallayout><simpara></simpara> +{title#}</para></formalpara> +endif::doctype-manpage[] +endif::docbook-xsl-172[] endif::backend-docbook[] ifdef::doctype-manpage[] diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 746646bb3d..45885bbbb2 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -134,7 +134,8 @@ endif::git-format-patch[] --diff-filter=[ACDMRTUXB*]:: Select only files that are Added (`A`), Copied (`C`), Deleted (`D`), Modified (`M`), Renamed (`R`), have their - type (mode) changed (`T`), are Unmerged (`U`), are + type (i.e. regular file, symlink, submodule, ...) changed (`T`), + are Unmerged (`U`), are Unknown (`X`), or have had their pairing Broken (`B`). Any combination of the filter characters may be used. When `*` (All-or-none) is added to the combination, all diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt index 2b821f2a1d..4b3c2b0b06 100644 --- a/Documentation/git-check-attr.txt +++ b/Documentation/git-check-attr.txt @@ -22,6 +22,56 @@ OPTIONS arguments as path names. If not supplied, only the first argument will be treated as an attribute. +OUTPUT +------ + +The output is of the form: +<path> COLON SP <attribute> COLON SP <info> LF + +Where <path> is the path of a file being queried, <attribute> is an attribute +being queried and <info> can be either: + +'unspecified';; when the attribute is not defined for the path. +'unset';; when the attribute is defined to false. +'set';; when the attribute is defined to true. +<value>;; when a value has been assigned to the attribute. + +EXAMPLES +-------- + +In the examples, the following '.gitattributes' file is used: +--------------- +*.java diff=java -crlf myAttr +NoMyAttr.java !myAttr +README caveat=unspecified +--------------- + +* Listing a single attribute: +--------------- +$ git check-attr diff org/example/MyClass.java +org/example/MyClass.java: diff: java +--------------- + +* Listing multiple attributes for a file: +--------------- +$ git check-attr crlf diff myAttr -- org/example/MyClass.java +org/example/MyClass.java: crlf: unset +org/example/MyClass.java: diff: java +org/example/MyClass.java: myAttr: set +--------------- + +* Listing attribute for multiple files: +--------------- +$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java +org/example/MyClass.java: myAttr: set +org/example/NoMyAttr.java: myAttr: unspecified +--------------- + +* Not all values are equally unambiguous: +--------------- +$ git check-attr caveat README +README: caveat: unspecified +--------------- SEE ALSO -------- diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 0e25bb8627..79be4f1c00 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -92,7 +92,8 @@ OPTIONS -s:: --signoff:: - Add Signed-off-by line at the end of the commit message. + Add Signed-off-by line by the commiter at the end of the commit + log message. -n:: --no-verify:: diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 53da9b4f6b..37fff208ff 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -163,8 +163,8 @@ few exceptions. Even though... `ident` ^^^^^^^ -When the attribute `ident` is set to a path, git replaces -`$Id$` in the blob object with `$Id:`, followed by +When the attribute `ident` is set for a path, git replaces +`$Id$` in the blob object with `$Id:`, followed by the 40-character hexadecimal blob object name, followed by a dollar sign `$` upon checkout. Any byte sequence that begins with `$Id:` and ends with `$` in the worktree file is replaced @@ -213,6 +213,9 @@ with `crlf`, and then `ident` and fed to `filter`. Generating diff text ~~~~~~~~~~~~~~~~~~~~ +`diff` +^^^^^^ + The attribute `diff` affects if 'git-diff' generates textual patch for the path or just says `Binary files differ`. It also can affect what line is shown on the hunk header `@@ -k,l +n,m @@` @@ -323,6 +326,9 @@ patterns are available: Performing a three-way merge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`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`. @@ -1355,7 +1355,7 @@ install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK @@ -1 +1 @@ -Documentation/RelNotes-1.6.0.3.txt
\ No newline at end of file +Documentation/RelNotes-1.6.0.4.txt
\ No newline at end of file @@ -338,5 +338,7 @@ int write_archive(int argc, const char **argv, const char *prefix, parse_treeish_arg(argv, &args, prefix); parse_pathspec_arg(argv + 1, &args); + git_config(git_default_config, NULL); + return ar->write_archive(&args); } @@ -129,7 +129,9 @@ void create_branch(const char *head, die("Cannot setup tracking information; starting point is not a branch."); break; case 1: - /* Unique completion -- good */ + /* Unique completion -- good, only if it is a real ref */ + if (track == BRANCH_TRACK_EXPLICIT && !strcmp(real_ref, "HEAD")) + die("Cannot setup tracking information; starting point is not a branch."); break; default: die("Ambiguous object name: '%s'.", start_name); diff --git a/builtin-archive.c b/builtin-archive.c index 432ce2acc6..5ceec433fd 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -111,8 +111,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix) { const char *remote = NULL; - git_config(git_default_config, NULL); - remote = extract_remote_arg(&argc, argv); if (remote) return run_remote_archiver(remote, argc, argv); diff --git a/builtin-checkout.c b/builtin-checkout.c index c4fc2b2c56..1deda927cd 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -565,6 +565,18 @@ no_reference: return checkout_paths(source_tree, pathspec); } + if (opts.new_branch) { + struct strbuf buf; + strbuf_init(&buf, 0); + strbuf_addstr(&buf, "refs/heads/"); + strbuf_addstr(&buf, opts.new_branch); + if (!get_sha1(buf.buf, rev)) + die("git checkout: branch %s already exists", opts.new_branch); + if (check_ref_format(buf.buf)) + die("git checkout: we do not like '%s' as a branch name.", opts.new_branch); + strbuf_release(&buf); + } + if (new.name && !new.commit) { die("Cannot switch branch to a non-commit."); } diff --git a/builtin-commit.c b/builtin-commit.c index e2a7e48b1c..b563a0d67c 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -320,7 +320,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) die("unable to write new_index file"); fd = hold_lock_file_for_update(&false_lock, - git_path("next-index-%d", getpid()), 1); + git_path("next-index-%d", getpid()), + LOCK_DIE_ON_ERROR); create_base_index(); add_remove_files(&partial); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 85509f5ee5..21ce3e0163 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -813,7 +813,8 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, ) die("shallow file was changed during fetch"); - fd = hold_lock_file_for_update(&lock, shallow, 1); + fd = hold_lock_file_for_update(&lock, shallow, + LOCK_DIE_ON_ERROR); if (!write_shallow_commits(fd, 0)) { unlink(shallow); rollback_lock_file(&lock); diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 4004e73e40..b0dddbee4f 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1377,7 +1377,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, memset(array, 0, array_size); for (;;) { - struct object_entry *entry = *list++; + struct object_entry *entry; struct unpacked *n = array + idx; int j, max_depth, best_base = -1; @@ -1386,6 +1386,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, progress_unlock(); break; } + entry = *list++; (*list_size)--; if (!entry->preferred_base) { (*processed)++; diff --git a/builtin-revert.c b/builtin-revert.c index 27881e9493..786a956f26 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -269,7 +269,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) int i; char *oneline, *reencoded_message = NULL; const char *message, *encoding; - const char *defmsg = xstrdup(git_path("MERGE_MSG")); + char *defmsg = xstrdup(git_path("MERGE_MSG")); git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; @@ -338,7 +338,8 @@ static int revert_or_cherry_pick(int argc, const char **argv) * reverse of it if we are revert. */ - msg_fd = hold_lock_file_for_update(&msg_file, defmsg, 1); + msg_fd = hold_lock_file_for_update(&msg_file, defmsg, + LOCK_DIE_ON_ERROR); encoding = get_encoding(message); if (!encoding) @@ -426,6 +427,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) return execv_git_cmd(args); } free(reencoded_message); + free(defmsg); return 0; } diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 2af9f29341..301f230432 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -132,7 +132,13 @@ static struct ref *remote_refs, **remote_tail; static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct ref *ref; - int len = strlen(refname) + 1; + int len; + + /* we already know it starts with refs/ to get here */ + if (check_ref_format(refname + 5)) + return 0; + + len = strlen(refname) + 1; ref = xcalloc(1, sizeof(*ref) + len); hashcpy(ref->new_sha1, sha1); memcpy(ref->name, refname, len); @@ -186,7 +186,8 @@ int create_bundle(struct bundle_header *header, const char *path, if (bundle_to_stdout) bundle_fd = 1; else - bundle_fd = hold_lock_file_for_update(&lock, path, 1); + bundle_fd = hold_lock_file_for_update(&lock, path, + LOCK_DIE_ON_ERROR); /* write signature */ write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature)); @@ -411,6 +411,8 @@ struct lock_file { char on_list; char filename[PATH_MAX]; }; +#define LOCK_DIE_ON_ERROR 1 +#define LOCK_NODEREF 2 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int hold_lock_file_for_append(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 751e273e1a..39a1ce5a39 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1410,6 +1410,8 @@ _git_shortlog () _git_show () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --pretty=*) diff --git a/contrib/examples/git-remote.perl b/contrib/examples/git-remote.perl index 36bd54c985..b17952a785 100755 --- a/contrib/examples/git-remote.perl +++ b/contrib/examples/git-remote.perl @@ -309,7 +309,7 @@ sub update_remote { } } } else { - print STDERR "Remote group $name does not exists.\n"; + print STDERR "Remote group $name does not exist.\n"; exit(1); } for (@remotes) { diff --git a/contrib/stats/packinfo.pl b/contrib/stats/packinfo.pl index f4a7b62cd9..be188c0f11 100755 --- a/contrib/stats/packinfo.pl +++ b/contrib/stats/packinfo.pl @@ -1,9 +1,9 @@ #!/usr/bin/perl # # This tool will print vaguely pretty information about a pack. It -# expects the output of "git-verify-pack -v" as input on stdin. +# expects the output of "git verify-pack -v" as input on stdin. # -# $ git-verify-pack -v | packinfo.pl +# $ git verify-pack -v | packinfo.pl # # This prints some full-pack statistics; currently "all sizes", "all # path sizes", "tree sizes", "tree path sizes", and "depths". @@ -20,7 +20,7 @@ # # When run as: # -# $ git-verify-pack -v | packinfo.pl -tree +# $ git verify-pack -v | packinfo.pl -tree # # the trees of objects are output along with the stats. This looks # like: @@ -43,7 +43,7 @@ # # When run as: # -# $ git-verify-pack -v | packinfo.pl -tree -filenames +# $ git verify-pack -v | packinfo.pl -tree -filenames # # it adds filenames to the tree. Getting this information is slow: # @@ -58,7 +58,7 @@ # # When run as: # -# $ git-verify-pack -v | packinfo.pl -dump +# $ git verify-pack -v | packinfo.pl -dump # # it prints out "sha1 size pathsize depth" for each sha1 in lexical # order. @@ -106,7 +106,7 @@ while (<STDIN>) { } if ($filenames && ($tree || $dump)) { - open(NAMES, "git-name-rev --all|"); + open(NAMES, "git name-rev --all|"); while (<NAMES>) { if (/^(\S+)\s+(.*)$/) { my ($sha1, $name) = ($1, $2); @@ -117,7 +117,7 @@ if ($filenames && ($tree || $dump)) { for my $commit (@commits) { my $name = $names{$commit}; - open(TREE, "git-ls-tree -t -r $commit|"); + open(TREE, "git ls-tree -t -r $commit|"); print STDERR "Plumbing tree $name\n"; while (<TREE>) { if (/^(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 1b2ebb4001..168a95b541 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -493,7 +493,7 @@ void diffcore_rename(struct diff_options *options) if ((num_create > rename_limit && num_src > rename_limit) || (num_create * num_src > rename_limit * rename_limit)) { if (options->warn_on_too_large_rename) - warning("too many files, skipping inexact rename detection"); + warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src); goto cleanup; } diff --git a/git-add--interactive.perl b/git-add--interactive.perl index da768ee7ac..b0223c3419 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -811,11 +811,16 @@ EOF } sub patch_update_cmd { - my @mods = grep { !($_->{BINARY}) } list_modified('file-only'); + my @all_mods = list_modified('file-only'); + my @mods = grep { !($_->{BINARY}) } @all_mods; my @them; if (!@mods) { - print STDERR "No changes.\n"; + if (@all_mods) { + print STDERR "Only binary files changed.\n"; + } else { + print STDERR "No changes.\n"; + } return 0; } if ($patch_mode) { diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl index 78f344f08f..a479b2f285 100644 --- a/git-gui/lib/spellcheck.tcl +++ b/git-gui/lib/spellcheck.tcl @@ -80,7 +80,7 @@ method _connect {pipe_fd} { error_popup [strcat [mc "Unrecognized spell checker"] ":\n\n$s_version"] return } - set s_version [string range $s_version 5 end] + set s_version [string range [string trim $s_version] 5 end] regexp \ {International Ispell Version .* \(but really (Aspell .*?)\)$} \ $s_version _junk s_version diff --git a/git-send-email.perl b/git-send-email.perl index d2fd899076..18529c76e6 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -407,10 +407,9 @@ for my $f (@ARGV) { push @files, grep { -f $_ } map { +$f . "/" . $_ } sort readdir(DH); - + closedir(DH); } elsif (-f $f or -p $f) { push @files, $f; - } else { print STDERR "Skipping $f - not found.\n"; } diff --git a/git-svn.perl b/git-svn.perl index 33e1b503c4..56238dad08 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1126,7 +1126,7 @@ sub read_repo_config { my $v = $opts->{$o}; my ($key) = ($o =~ /^([a-zA-Z\-]+)/); $key =~ s/-//g; - my $arg = 'git-config'; + my $arg = 'git config'; $arg .= ' --int' if ($o =~ /[:=]i$/); $arg .= ' --bool' if ($o !~ /[:=][sfi]$/); if (ref $v eq 'ARRAY') { @@ -2202,7 +2202,7 @@ sub do_git_commit { } die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o; - my @exec = ('git-commit-tree', $tree); + my @exec = ('git', 'commit-tree', $tree); foreach ($self->get_commit_parents($log_entry)) { push @exec, '-p', $_; } diff --git a/index-pack.c b/index-pack.c index 2a366206a4..c99a1a152c 100644 --- a/index-pack.c +++ b/index-pack.c @@ -879,10 +879,26 @@ int main(int argc, char **argv) char *index_name_buf = NULL, *keep_name_buf = NULL; struct pack_idx_entry **idx_objects; unsigned char pack_sha1[20]; - int nongit = 0; - setup_git_directory_gently(&nongit); - git_config(git_index_pack_config, NULL); + /* + * We wish to read the repository's config file if any, and + * for that it is necessary to call setup_git_directory_gently(). + * However if the cwd was inside .git/objects/pack/ then we need + * to go back there or all the pack name arguments will be wrong. + * And in that case we cannot rely on any prefix returned by + * setup_git_directory_gently() either. + */ + { + char cwd[PATH_MAX+1]; + int nongit; + + if (!getcwd(cwd, sizeof(cwd)-1)) + die("Unable to get current working directory"); + setup_git_directory_gently(&nongit); + git_config(git_index_pack_config, NULL); + if (chdir(cwd)) + die("Cannot come back to cwd"); + } for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/lockfile.c b/lockfile.c index 4023797b00..6d75608693 100644 --- a/lockfile.c +++ b/lockfile.c @@ -121,15 +121,17 @@ static char *resolve_symlink(char *p, size_t s) } -static int lock_file(struct lock_file *lk, const char *path) +static int lock_file(struct lock_file *lk, const char *path, int flags) { - if (strlen(path) >= sizeof(lk->filename)) return -1; + if (strlen(path) >= sizeof(lk->filename)) + return -1; strcpy(lk->filename, path); /* * subtract 5 from size to make sure there's room for adding * ".lock" for the lock file name */ - resolve_symlink(lk->filename, sizeof(lk->filename)-5); + if (!(flags & LOCK_NODEREF)) + resolve_symlink(lk->filename, sizeof(lk->filename)-5); strcat(lk->filename, ".lock"); lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { @@ -155,21 +157,21 @@ static int lock_file(struct lock_file *lk, const char *path) return lk->fd; } -int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) +int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags) { - int fd = lock_file(lk, path); - if (fd < 0 && die_on_error) + int fd = lock_file(lk, path, flags); + if (fd < 0 && (flags & LOCK_DIE_ON_ERROR)) die("unable to create '%s.lock': %s", path, strerror(errno)); return fd; } -int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on_error) +int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags) { int fd, orig_fd; - fd = lock_file(lk, path); + fd = lock_file(lk, path, flags); if (fd < 0) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) die("unable to create '%s.lock': %s", path, strerror(errno)); return fd; } @@ -177,13 +179,13 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on orig_fd = open(path, O_RDONLY); if (orig_fd < 0) { if (errno != ENOENT) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) die("cannot open '%s' for copying", path); close(fd); return error("cannot open '%s' for copying", path); } } else if (copy_fd(orig_fd, fd)) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) exit(128); close(fd); return -1; @@ -215,7 +217,10 @@ int commit_lock_file(struct lock_file *lk) int hold_locked_index(struct lock_file *lk, int die_on_error) { - return hold_lock_file_for_update(lk, get_index_file(), die_on_error); + return hold_lock_file_for_update(lk, get_index_file(), + die_on_error + ? LOCK_DIE_ON_ERROR + : 0); } void set_alternate_index_output(const char *name) diff --git a/pack-refs.c b/pack-refs.c index 848d311c2b..2c76fb181f 100644 --- a/pack-refs.c +++ b/pack-refs.c @@ -89,7 +89,8 @@ int pack_refs(unsigned int flags) memset(&cbdata, 0, sizeof(cbdata)); cbdata.flags = flags; - fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), 1); + fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), + LOCK_DIE_ON_ERROR); cbdata.refs_file = fdopen(fd, "w"); if (!cbdata.refs_file) die("unable to create ref-pack file structure (%s)", @@ -348,7 +348,7 @@ int normalize_absolute_path(char *buf, const char *path) goto next; } - memcpy(dst, comp_start, comp_len); + memmove(dst, comp_start, comp_len); dst += comp_len; next: comp_start = comp_end; @@ -790,7 +790,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char struct ref_lock *lock; struct stat st; int last_errno = 0; - int type; + int type, lflags; int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); lock = xcalloc(1, sizeof(struct ref_lock)); @@ -830,8 +830,11 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char lock->lk = xcalloc(1, sizeof(struct lock_file)); - if (flags & REF_NODEREF) + lflags = LOCK_DIE_ON_ERROR; + if (flags & REF_NODEREF) { ref = orig_ref; + lflags |= LOCK_NODEREF; + } lock->ref_name = xstrdup(ref); lock->orig_ref_name = xstrdup(orig_ref); ref_file = git_path("%s", ref); @@ -845,8 +848,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char error("unable to create directory for %s", ref_file); goto error_return; } - lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1); + lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags); return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; error_return: @@ -346,7 +346,8 @@ int setup_rerere(struct string_list *merge_rr) return -1; merge_rr_path = xstrdup(git_path("MERGE_RR")); - fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1); + fd = hold_lock_file_for_update(&write_lock, merge_rr_path, + LOCK_DIE_ON_ERROR); read_rr(merge_rr); return fd; } diff --git a/sha1_file.c b/sha1_file.c index e2cb342a32..12fc767ee5 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -385,7 +385,7 @@ static void read_info_alternates(const char * relative_base, int depth) void add_to_alternates_file(const char *reference) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), 1); + int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR); char *alt = mkpath("%s/objects\n", reference); write_or_die(fd, alt, strlen(alt)); if (commit_lock_file(lock)) @@ -2322,6 +2322,7 @@ int force_object_loose(const unsigned char *sha1, time_t mtime) enum object_type type; char hdr[32]; int hdrlen; + int ret; if (has_loose_object(sha1)) return 0; @@ -2329,7 +2330,10 @@ int force_object_loose(const unsigned char *sha1, time_t mtime) if (!buf) return error("cannot read sha1_file for %s", sha1_to_hex(sha1)); hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1; - return write_loose_object(sha1, hdr, hdrlen, buf, len, mtime); + ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime); + free(buf); + + return ret; } int has_pack_index(const unsigned char *sha1) diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index dc85e8b60a..653362ba22 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -7,6 +7,9 @@ test_description='Test shared repository initialization' . ./test-lib.sh +# Remove a default ACL from the test dir if possible. +setfacl -k . 2>/dev/null + # User must have read permissions to the repo -> failure on --shared=0400 test_expect_success 'shared = 0400 (faulty permission u-w)' ' mkdir sub && ( @@ -17,6 +20,10 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' ' test $ret != "0" ' +modebits () { + ls -l "$1" | sed -e 's|^\(..........\).*|\1|' +} + for u in 002 022 do test_expect_success "shared=1 does not clear bits preset by umask $u" ' @@ -82,8 +89,7 @@ do rm -f .git/info/refs && git update-server-info && - actual="$(ls -l .git/info/refs)" && - actual=${actual%% *} && + actual="$(modebits .git/info/refs)" && test "x$actual" = "x-$y" || { ls -lt .git/info false @@ -95,8 +101,7 @@ do rm -f .git/info/refs && git update-server-info && - actual="$(ls -l .git/info/refs)" && - actual=${actual%% *} && + actual="$(modebits .git/info/refs)" && test "x$actual" = "x-$x" || { ls -lt .git/info false diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 99fff973eb..398bf4b5d8 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -65,7 +65,14 @@ test_expect_success 'custom pattern' ' test_expect_success 'last regexp must not be negated' ' git config diff.java.funcname "!static" && - test_must_fail git diff --no-index Beer.java Beer-correct.java + git diff --no-index Beer.java Beer-correct.java 2>&1 | + grep "fatal: Last expression must not be negated:" +' + +test_expect_success 'pattern which matches to end of line' ' + git config diff.java.funcname "Beer$" && + git diff --no-index Beer.java Beer-correct.java | + grep "^@@.*@@ Beer" ' test_expect_success 'alternation in pattern' ' diff --git a/t/t4128-apply-root.sh b/t/t4128-apply-root.sh index bc7a8a8689..8f6aea48d8 100755 --- a/t/t4128-apply-root.sh +++ b/t/t4128-apply-root.sh @@ -72,7 +72,7 @@ test_expect_success 'apply --directory (delete file)' ' echo content >some/sub/dir/delfile && git add some/sub/dir/delfile && git apply --directory=some/sub/dir/ --index patch && - ! git ls-files | grep delfile + ! (git ls-files | grep delfile) ' cat > patch << 'EOF' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index e395ff4e34..c942c8be85 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -58,6 +58,11 @@ test_expect_success \ git commit-tree $treeid </dev/null)' test_expect_success \ + 'create bare clone' \ + 'git clone --bare . bare.git && + cp .gitattributes bare.git/info/attributes' + +test_expect_success \ 'remove ignored file' \ 'rm a/ignored' @@ -74,10 +79,18 @@ test_expect_success \ 'diff b.tar b2.tar' test_expect_success \ + 'git archive in a bare repo' \ + '(cd bare.git && git archive HEAD) >b3.tar' + +test_expect_success \ + 'git archive vs. the same in a bare repo' \ + 'test_cmp b.tar b3.tar' + +test_expect_success \ 'validate file modification time' \ 'mkdir extract && "$TAR" xf b.tar -C extract a/a && - perl -e '\''print((stat("extract/a/a"))[9], "\n")'\'' >b.mtime && + test-chmtime -v +0 extract/a/a |cut -f 1 >b.mtime && echo "1117231200" >expected.mtime && diff expected.mtime b.mtime' @@ -151,6 +164,14 @@ test_expect_success \ 'git archive --format=zip' \ 'git archive --format=zip HEAD >d.zip' +test_expect_success \ + 'git archive --format=zip in a bare repo' \ + '(cd bare.git && git archive --format=zip HEAD) >d1.zip' + +test_expect_success \ + 'git archive --format=zip vs. the same in a bare repo' \ + 'test_cmp d.zip d1.zip' + $UNZIP -v >/dev/null 2>&1 if [ $? -eq 127 ]; then echo "Skipping ZIP tests, because unzip was not found" diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 6424db1f28..344ab25b8b 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -177,4 +177,14 @@ test_expect_success \ ".git/objects/pack/pack-${pack1}.pack" 2>&1) && echo "$err" | grep "CRC mismatch"' +test_expect_success 'running index-pack in the object store' ' + rm -f .git/objects/pack/* && + cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack && + ( + cd .git/objects/pack + git index-pack pack-${pack1}.pack + ) && + test -f .git/objects/pack/pack-${pack1}.idx +' + test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index fbec70d3c6..c9abed6a2b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -330,12 +330,26 @@ test_expect_success \ test "$(git config branch.track2.merge)" git config branch.autosetupmerge false' -test_expect_success \ - 'checkout w/--track from non-branch HEAD fails' ' - git checkout -b delete-me master && - rm .git/refs/heads/delete-me && - test refs/heads/delete-me = "$(git symbolic-ref HEAD)" && - test_must_fail git checkout --track -b track' +test_expect_success 'checkout w/--track from non-branch HEAD fails' ' + git checkout master^0 && + test_must_fail git symbolic-ref HEAD && + test_must_fail git checkout --track -b track && + test_must_fail git rev-parse --verify track && + test_must_fail git symbolic-ref HEAD && + test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)" +' + +test_expect_success 'detach a symbolic link HEAD' ' + git checkout master && + git config --bool core.prefersymlinkrefs yes && + git checkout side && + git checkout master && + it=$(git symbolic-ref HEAD) && + test "z$it" = zrefs/heads/master && + here=$(git rev-parse --verify refs/heads/master) && + git checkout side^ && + test "z$(git rev-parse --verify refs/heads/master)" = "z$here" +' test_expect_success 'checkout an unmerged path should fail' ' rm -f .git/index && @@ -359,4 +373,14 @@ test_expect_success 'checkout an unmerged path should fail' ' test_cmp sample file ' +test_expect_success 'failing checkout -b should not break working tree' ' + git reset --hard master && + git symbolic-ref HEAD refs/heads/master && + test_must_fail git checkout -b renamer side^ && + test $(git symbolic-ref HEAD) = refs/heads/master && + git diff --exit-code && + git diff --cached --exit-code + +' + test_done diff --git a/test-chmtime.c b/test-chmtime.c index 90da448ebe..d5358cbaac 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -1,39 +1,83 @@ +/* + * This program can either change modification time of the given + * file(s) or just print it. The program does not change atime nor + * ctime (their values are explicitely preserved). + * + * The mtime can be changed to an absolute value: + * + * test-chmtime =<seconds> file... + * + * Relative to the current time as returned by time(3): + * + * test-chmtime =+<seconds> (or =-<seconds>) file... + * + * Or relative to the current mtime of the file: + * + * test-chmtime <seconds> file... + * test-chmtime +<seconds> (or -<seconds>) file... + * + * Examples: + * + * To just print the mtime use --verbose and set the file mtime offset to 0: + * + * test-chmtime -v +0 file + * + * To set the mtime to current time: + * + * test-chmtime =+0 file + * + */ #include "git-compat-util.h" #include <utime.h> -static const char usage_str[] = "(+|=|=+|=-|-)<seconds> <file>..."; +static const char usage_str[] = "-v|--verbose (+|=|=+|=-|-)<seconds> <file>..."; -int main(int argc, const char *argv[]) +static int timespec_arg(const char *arg, long int *set_time, int *set_eq) { - int i; - int set_eq; - long int set_time; char *test; - const char *timespec; - - if (argc < 3) - goto usage; - - timespec = argv[1]; - set_eq = (*timespec == '=') ? 1 : 0; - if (set_eq) { + const char *timespec = arg; + *set_eq = (*timespec == '=') ? 1 : 0; + if (*set_eq) { timespec++; if (*timespec == '+') { - set_eq = 2; /* relative "in the future" */ + *set_eq = 2; /* relative "in the future" */ timespec++; } } - set_time = strtol(timespec, &test, 10); + *set_time = strtol(timespec, &test, 10); if (*test) { - fprintf(stderr, "Not a base-10 integer: %s\n", argv[1] + 1); - goto usage; + fprintf(stderr, "Not a base-10 integer: %s\n", arg + 1); + return 0; } - if ((set_eq && set_time < 0) || set_eq == 2) { + if ((*set_eq && *set_time < 0) || *set_eq == 2) { time_t now = time(NULL); - set_time += now; + *set_time += now; } + return 1; +} + +int main(int argc, const char *argv[]) +{ + static int verbose; - for (i = 2; i < argc; i++) { + int i = 1; + /* no mtime change by default */ + int set_eq = 0; + long int set_time = 0; + + if (argc < 3) + goto usage; + + if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) { + verbose = 1; + ++i; + } + if (timespec_arg(argv[i], &set_time, &set_eq)) + ++i; + else + goto usage; + + for (; i < argc; i++) { struct stat sb; struct utimbuf utb; @@ -46,7 +90,12 @@ int main(int argc, const char *argv[]) utb.actime = sb.st_atime; utb.modtime = set_eq ? set_time : sb.st_mtime + set_time; - if (utime(argv[i], &utb) < 0) { + if (verbose) { + uintmax_t mtime = utb.modtime < 0 ? 0: utb.modtime; + printf("%"PRIuMAX"\t%s\n", mtime, argv[i]); + } + + if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) { fprintf(stderr, "Failed to modify time on %s: %s\n", argv[i], strerror(errno)); return -1; diff --git a/unpack-trees.c b/unpack-trees.c index e59d144d28..e5749ef638 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -382,7 +382,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options o->merge_size = len; if (!dfc) - dfc = xcalloc(1, sizeof(struct cache_entry) + 1); + dfc = xcalloc(1, cache_entry_size(0)); o->df_conflict_entry = dfc; if (len) { diff --git a/xdiff-interface.c b/xdiff-interface.c index 2c81f40cb6..3bf83f81e3 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -179,11 +179,21 @@ struct ff_regs { static long ff_regexp(const char *line, long len, char *buffer, long buffer_size, void *priv) { - char *line_buffer = xstrndup(line, len); /* make NUL terminated */ + char *line_buffer; struct ff_regs *regs = priv; regmatch_t pmatch[2]; int result = 0, i; + /* Exclude terminating newline (and cr) from matching */ + if (len > 0 && line[len-1] == '\n') { + if (len > 1 && line[len-2] == '\r') + len -= 2; + else + len--; + } + + line_buffer = xstrndup(line, len); /* make NUL terminated */ + for (i = 0; i < regs->nr; i++) { struct ff_reg *reg = regs->array + i; if (reg->negate ^ !!regexec(®->re, |
