diff options
32 files changed, 292 insertions, 65 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-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); } 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-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 e839387629..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"; @@ -427,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); 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/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]; @@ -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; diff --git a/sha1_file.c b/sha1_file.c index 5cfae5d1ad..12fc767ee5 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -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 2275caa317..653362ba22 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -20,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" ' @@ -85,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 @@ -98,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/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 f93478f97f..c9abed6a2b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -373,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) { |