Code

Merge branch 'cr/reset-parseopt'
authorJunio C Hamano <gitster@pobox.com>
Sun, 9 Mar 2008 04:09:55 +0000 (20:09 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 9 Mar 2008 04:09:55 +0000 (20:09 -0800)
* cr/reset-parseopt:
  Make builtin-reset.c use parse_options.

41 files changed:
Documentation/RelNotes-1.5.4.4.txt
Documentation/RelNotes-1.5.5.txt
Documentation/config.txt
Documentation/git-mergetool.txt
Documentation/git-reflog.txt
Documentation/git-stash.txt
Documentation/git-whatchanged.txt
Documentation/git.txt
Documentation/pretty-options.txt
Documentation/technical/api-run-command.txt
Makefile
builtin-log.c
builtin-reflog.c
builtin-shortlog.c
contrib/completion/git-completion.bash
contrib/emacs/git.el
contrib/hooks/post-receive-email
fast-import.c
fsck.c
git-compat-util.h
git-cvsserver.perl
git-filter-branch.sh
git-gui/Makefile
git-merge.sh
git-mergetool.sh
git-send-email.perl
git-stash.sh
git-svn.perl
gitweb/gitweb.perl
ident.c
path.c
quote.c
refs.c
refs.h
run-command.c
t/t1410-reflog.sh
t/t3903-stash.sh
t/t7003-filter-branch.sh
t/t7610-mergetool.sh [new file with mode: 0644]
t/t9300-fast-import.sh
t/test-lib.sh

index 5635977c93b68b59f95c78058fecd8bd234b2693..89fa6d03bc038d6210e94d7fe9fbbffdbc84d883 100644 (file)
@@ -37,10 +37,30 @@ Fixes since v1.5.4.3
  * "git revert" did not properly fail when attempting to run with a
    dirty index.
 
-Also included are a handful documentation updates.
+ * "git merge --no-commit --no-ff <other>" incorrectly made commits.
+
+ * "git merge --squash --no-ff <other>", which is a nonsense combination
+   of options, was not rejected.
+
+ * "git ls-remote" and "git remote show" against an empty repository
+   failed, instead of just giving an empty result (regression).
+
+ * "git fast-import" did not handle a renamed path whose name needs to be
+   quoted, due to a bug in unquote_c_style() function.
+
+ * "git cvsexportcommit" was confused when multiple files with the same
+   basename needed to be pushed out in the same commit.
+
+ * "git daemon" did not send early errors to syslog.
 
----
-exec >/var/tmp/1
-echo O=$(git describe maint)
-O=v1.5.4.3-32-g0f2d447
-git shortlog --no-merges $O..maint
+ * "git log --merge" did not work well with --left-right option.
+
+ * "git svn" promprted for client cert password every time it accessed the
+   server.
+
+ * The reset command in "git fast-import" data stream was documented to
+   end with an optional LF, but it actually required one.
+
+ * "git svn dcommit/rebase" did not honor --rewrite-root option.
+
+Also included are a handful documentation updates.
index b57fa1eb1a5bfc1d03e59c90222e0b6ed96fe261..874dad9a4f04b2ce11c9a7449c60b322aa041a37 100644 (file)
@@ -160,13 +160,9 @@ Fixes since v1.5.4
 All of the fixes in v1.5.4 maintenance series are included in
 this release, unless otherwise noted.
 
- * "git-daemon" did not send early errors to syslog.
-
  * "git-http-push" did not allow deletion of remote ref with the usual
    "push <remote> :<branch>" syntax.
 
- * "git-log --merge" did not well work with --left-right option.
-
  * "git-rebase --abort" did not go back to the right location if
    "git-reset" was run during the "git-rebase" session.
 
index 4027726f2ee66ebad69412a5c8c6d1aef7f7463f..c5e094a9c4a31568e4efb2c70af7e7808ae63528 100644 (file)
@@ -556,6 +556,11 @@ format.suffix::
        `.patch`. Use this variable to change that suffix (make sure to
        include the dot if you want it).
 
+format.pretty::
+       The default pretty format for log/show/whatchanged command,
+       See linkgit:git-log[1], linkgit:git-show[1],
+       linkgit:git-whatchanged[1].
+
 gc.aggressiveWindow::
        The window size parameter used in the delta compression
        algorithm used by 'git gc --aggressive'.  This defaults
@@ -749,8 +754,10 @@ merge.summary::
 
 merge.tool::
        Controls which merge resolution program is used by
-       linkgit:git-mergetool[1].  Valid values are: "kdiff3", "tkdiff",
-       "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
+       linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
+       "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
+       "opendiff".  Any other value is treated is custom merge tool
+       and there must be a corresponing mergetool.<tool>.cmd option.
 
 merge.verbosity::
        Controls the amount of output shown by the recursive merge
@@ -777,6 +784,31 @@ mergetool.<tool>.path::
        Override the path for the given tool.  This is useful in case
        your tool is not in the PATH.
 
+mergetool.<tool>.cmd::
+       Specify the command to invoke the specified merge tool.  The
+       specified command is evaluated in shell with the following
+       variables available: 'BASE' is the name of a temporary file
+       containing the common base of the files to be merged, if available;
+       'LOCAL' is the name of a temporary file containing the contents of
+       the file on the current branch; 'REMOTE' is the name of a temporary
+       file containing the contents of the file from the branch being
+       merged; 'MERGED' contains the name of the file to which the merge
+       tool should write the results of a successful merge.
+
+mergetool.<tool>.trustExitCode::
+       For a custom merge command, specify whether the exit code of
+       the merge command can be used to determine whether the merge was
+       successful.  If this is not set to true then the merge target file
+       timestamp is checked and the merge assumed to have been successful
+       if the file has been updated, otherwise the user is prompted to
+       indicate the success of the merge.
+
+mergetool.keepBackup::
+       After performing a merge, the original file with conflict markers
+       can be saved as a file with a `.orig` extension.  If this variable
+       is set to `false` then this file is not preserved.  Defaults to
+       `true` (i.e. keep the backup files).
+
 pack.window::
        The size of the window used by linkgit:git-pack-objects[1] when no
        window size is given on the command line. Defaults to 10.
@@ -864,15 +896,15 @@ remote.<name>.skipDefaultUpdate::
 
 remote.<name>.receivepack::
        The default program to execute on the remote side when pushing.  See
-       option \--exec of linkgit:git-push[1].
+       option \--receive-pack of linkgit:git-push[1].
 
 remote.<name>.uploadpack::
        The default program to execute on the remote side when fetching.  See
-       option \--exec of linkgit:git-fetch-pack[1].
+       option \--upload-pack of linkgit:git-fetch-pack[1].
 
 remote.<name>.tagopt::
-       Setting this value to --no-tags disables automatic tag following when fetching
-       from remote <name>
+       Setting this value to \--no-tags disables automatic tag following when
+       fetching from remote <name>
 
 remotes.<group>::
        The list of remotes which are fetched by "git remote update
index 50f106ec5b49b6d46f4be6fa012148b24d6e8801..8ed44947ef877d2f960b1506a39ab0c166cce514 100644 (file)
@@ -12,12 +12,12 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Use 'git mergetool' to run one of several merge utilities to resolve
+Use `git mergetool` to run one of several merge utilities to resolve
 merge conflicts.  It is typically run after linkgit:git-merge[1].
 
 If one or more <file> parameters are given, the merge tool program will
 be run to resolve differences on each file.  If no <file> names are
-specified, 'git mergetool' will run the merge tool program on every file
+specified, `git mergetool` will run the merge tool program on every file
 with merge conflicts.
 
 OPTIONS
@@ -27,16 +27,38 @@ OPTIONS
        Valid merge tools are:
        kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff
 +
-If a merge resolution program is not specified, 'git mergetool'
-will use the configuration variable merge.tool.  If the
-configuration variable merge.tool is not set, 'git mergetool'
+If a merge resolution program is not specified, `git mergetool`
+will use the configuration variable `merge.tool`.  If the
+configuration variable `merge.tool` is not set, `git mergetool`
 will pick a suitable default.
 +
 You can explicitly provide a full path to the tool by setting the
-configuration variable mergetool.<tool>.path. For example, you
+configuration variable `mergetool.<tool>.path`. For example, you
 can configure the absolute path to kdiff3 by setting
-mergetool.kdiff3.path. Otherwise, 'git mergetool' assumes the tool
-is available in PATH.
+`mergetool.kdiff3.path`. Otherwise, `git mergetool` assumes the
+tool is available in PATH.
++
+Instead of running one of the known merge tool programs
+`git mergetool` can be customized to run an alternative program
+by specifying the command line to invoke in a configration
+variable `mergetool.<tool>.cmd`.
++
+When `git mergetool` is invoked with this tool (either through the
+`-t` or `--tool` option or the `merge.tool` configuration
+variable) the configured command line will be invoked with `$BASE`
+set to the name of a temporary file containing the common base for
+the merge, if available; `$LOCAL` set to the name of a temporary
+file containing the contents of the file on the current branch;
+`$REMOTE` set to the name of a temporary file containing the
+contents of the file to be merged, and `$MERGED` set to the name
+of the file to which the merge tool should write the result of the
+merge resolution.
++
+If the custom merge tool correctly indicates the success of a
+merge resolution with its exit code then the configuration
+variable `mergetool.<tool>.trustExitCode` can be set to `true`.
+Otherwise, `git mergetool` will prompt the user to indicate the
+success of the resolution after the custom tool has exited.
 
 Author
 ------
index f9bba36c2309d5b4a9587d0f4a406cf57fcd8348..047e3ce14dfac6f1848fa8f1772202c26efa1055 100644 (file)
@@ -19,6 +19,8 @@ depending on the subcommand:
 git reflog expire [--dry-run] [--stale-fix] [--verbose]
        [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
 
+git reflog delete ref@\{specifier\}...
+
 git reflog [show] [log-options] [<ref>]
 
 Reflog is a mechanism to record when the tip of branches are
@@ -43,6 +45,9 @@ two moves ago", `master@\{one.week.ago\}` means "where master used to
 point to one week ago", and so on. See linkgit:git-rev-parse[1] for
 more details.
 
+To delete single entries from the reflog, use the subcommand "delete"
+and specify the _exact_ entry (e.g. ``git reflog delete master@\{2\}'').
+
 
 OPTIONS
 -------
@@ -75,6 +80,15 @@ them.
 --all::
        Instead of listing <refs> explicitly, prune all refs.
 
+--updateref::
+       Update the ref with the sha1 of the top reflog entry (i.e.
+       <ref>@\{0\}) after expiring or deleting.
+
+--rewrite::
+       While expiring or deleting, adjust each reflog entry to ensure
+       that the `old` sha1 field points to the `new` sha1 field of the
+       previous entry.
+
 --verbose::
        Print extra information on screen.
 
index 48e6f5a3f7a85e886639381dfa70434ecdeccfc2..8dc35d493e81bc0c5515ec279dbe95c464c57469 100644 (file)
@@ -8,7 +8,7 @@ git-stash - Stash the changes in a dirty working directory away
 SYNOPSIS
 --------
 [verse]
-'git-stash' (list | show [<stash>] | apply [<stash>] | clear)
+'git-stash' (list | show [<stash>] | apply [<stash>] | clear | drop [<stash>] | pop [<stash>])
 'git-stash' [save [<message>]]
 
 DESCRIPTION
@@ -85,6 +85,17 @@ clear::
        Remove all the stashed states. Note that those states will then
        be subject to pruning, and may be difficult or impossible to recover.
 
+drop [<stash>]::
+
+       Remove a single stashed state from the stash list. When no `<stash>`
+       is given, it removes the latest one. i.e. `stash@\{0}`
+
+pop [<stash>]::
+
+       Remove a single stashed state from the stash list and apply on top
+       of the current working tree state. When no `<stash>` is given,
+       `stash@\{0}` is assumed. See also `apply`.
+
 
 DISCUSSION
 ----------
index 54947b676969585c4641bf7a4f538623e059dd15..a6e7bd4c8b99ad2d6a19acf4a412b81580ef3027 100644 (file)
@@ -38,11 +38,6 @@ OPTIONS
        Show git internal diff output, but for the whole tree,
        not just the top level.
 
---pretty=<format>::
-       Controls the output format for the commit logs.
-       <format> can be one of 'raw', 'medium', 'short', 'full',
-       and 'oneline'.
-
 -m::
        By default, differences for merge commits are not shown.
        With this flag, show differences to that commit from all
@@ -51,6 +46,10 @@ OPTIONS
 However, it is not very useful in general, although it
 *is* useful on a file-by-file basis.
 
+include::pretty-options.txt[]
+
+include::pretty-formats.txt[]
+
 Examples
 --------
 git-whatchanged -p v2.6.12.. include/scsi drivers/scsi::
index 741ae0e4c8ec9a3aaaef19430b0f76e4baedb546..3ed24d449a1f277c40dbb49654a196e38d1fa3e4 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.5.4.3/git.html[documentation for release 1.5.4.3]
+* link:v1.5.4.4/git.html[documentation for release 1.5.4.4]
 
 * release notes for
+  link:RelNotes-1.5.4.4.txt[1.5.4.4],
   link:RelNotes-1.5.4.3.txt[1.5.4.3],
   link:RelNotes-1.5.4.2.txt[1.5.4.2],
   link:RelNotes-1.5.4.1.txt[1.5.4.1],
index 973d8dd733f954abf93aac7c68efef1154e9f315..6d66c74cc11e6622892061f8328d04dfe38f87bf 100644 (file)
@@ -4,6 +4,9 @@
        where '<format>' can be one of 'oneline', 'short', 'medium',
        'full', 'fuller', 'email', 'raw' and 'format:<string>'.
        When omitted, the format defaults to 'medium'.
++
+Note: you can specify the default pretty format in the repository
+configuration (see linkgit:git-config[1]).
 
 --abbrev-commit::
        Instead of showing the full 40-byte hexadecimal commit object
index fde3b453211030b7256ccedd100970ef712338bd..c364a22c8f98f6fbb71d4059f7458ed0fa78ed43 100644 (file)
@@ -111,9 +111,10 @@ stderr as follows:
        .no_stdin, .no_stdout, .no_stderr: The respective channel is
                redirected to /dev/null.
 
-       .stdout_to_stderr: stdout of the child is redirected to the
-               parent's stderr (i.e. *not* to what .err or
-               .no_stderr specify).
+       .stdout_to_stderr: stdout of the child is redirected to its
+               stderr. This happens after stderr is itself redirected.
+               So stdout will follow stderr to wherever it is
+               redirected.
 
 To modify the environment of the sub-process, specify an array of
 string pointers (NULL terminated) in .env:
index ca5aad963ca7b5565338f49ce1705c451216c8be..6e857e62c3d02fa2bfef7b9224e24d5b6a279c9c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -478,6 +478,7 @@ ifeq ($(uname_S),FreeBSD)
        NO_MEMMEM = YesPlease
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
+       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
@@ -747,6 +748,9 @@ ifdef THREADED_DELTA_SEARCH
        EXTLIBS += -lpthread
        LIB_OBJS += thread-utils.o
 endif
+ifdef DIR_HAS_BSD_GROUP_SEMANTICS
+       COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
+endif
 
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK=NoThanks
index fe8fc6f22a176a017c65ac6177f0bab890d8fce5..d983cbc7bc98f1b28332c18946e5111a6dcba9ab 100644 (file)
@@ -20,6 +20,7 @@
 
 static int default_show_root = 1;
 static const char *fmt_patch_subject_prefix = "PATCH";
+static const char *fmt_pretty;
 
 static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
 {
@@ -54,6 +55,8 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
+       if (fmt_pretty)
+               rev->commit_format = get_commit_format(fmt_pretty);
        rev->verbose_header = 1;
        DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
        rev->show_root_diff = default_show_root;
@@ -221,6 +224,8 @@ static int cmd_log_walk(struct rev_info *rev)
 
 static int git_log_config(const char *var, const char *value)
 {
+       if (!strcmp(var, "format.pretty"))
+               return git_config_string(&fmt_pretty, var, value);
        if (!strcmp(var, "format.subjectprefix")) {
                if (!value)
                        config_error_nonbool(var);
index ab53c8cb7c08298c3ab0f69bf600a70385dafa64..280e24e1514f2989b571acc768d7067cbb223933 100644 (file)
@@ -14,6 +14,8 @@
 
 static const char reflog_expire_usage[] =
 "git-reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+static const char reflog_delete_usage[] =
+"git-reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
 
 static unsigned long default_reflog_expire;
 static unsigned long default_reflog_expire_unreachable;
@@ -22,9 +24,12 @@ struct cmd_reflog_expire_cb {
        struct rev_info revs;
        int dry_run;
        int stalefix;
+       int rewrite;
+       int updateref;
        int verbose;
        unsigned long expire_total;
        unsigned long expire_unreachable;
+       int recno;
 };
 
 struct expire_reflog_cb {
@@ -32,6 +37,7 @@ struct expire_reflog_cb {
        const char *ref;
        struct commit *ref_commit;
        struct cmd_reflog_expire_cb *cmd;
+       unsigned char last_kept_sha1[20];
 };
 
 struct collected_reflog {
@@ -213,6 +219,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
        if (timestamp < cb->cmd->expire_total)
                goto prune;
 
+       if (cb->cmd->rewrite)
+               osha1 = cb->last_kept_sha1;
+
        old = new = NULL;
        if (cb->cmd->stalefix &&
            (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
@@ -230,6 +239,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                        goto prune;
        }
 
+       if (cb->cmd->recno && --(cb->cmd->recno) == 0)
+               goto prune;
+
        if (cb->newlog) {
                char sign = (tz < 0) ? '-' : '+';
                int zone = (tz < 0) ? (-tz) : tz;
@@ -237,6 +249,7 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                        sha1_to_hex(osha1), sha1_to_hex(nsha1),
                        email, timestamp, sign, zone,
                        message);
+               hashcpy(cb->last_kept_sha1, nsha1);
        }
        if (cb->cmd->verbose)
                printf("keep %s", message);
@@ -280,10 +293,20 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
                        status |= error("%s: %s", strerror(errno),
                                        newlog_path);
                        unlink(newlog_path);
+               } else if (cmd->updateref &&
+                       (write_in_full(lock->lock_fd,
+                               sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
+                        write_in_full(lock->lock_fd, "\n", 1) != 1 ||
+                        close_ref(lock) < 0)) {
+                       status |= error("Couldn't write %s",
+                               lock->lk->filename);
+                       unlink(newlog_path);
                } else if (rename(newlog_path, log_file)) {
                        status |= error("cannot rename %s to %s",
                                        newlog_path, log_file);
                        unlink(newlog_path);
+               } else if (cmd->updateref && commit_ref(lock)) {
+                       status |= error("Couldn't set %s", lock->ref_name);
                }
        }
        free(newlog_path);
@@ -358,6 +381,10 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                        cb.expire_unreachable = approxidate(arg + 21);
                else if (!strcmp(arg, "--stale-fix"))
                        cb.stalefix = 1;
+               else if (!strcmp(arg, "--rewrite"))
+                       cb.rewrite = 1;
+               else if (!strcmp(arg, "--updateref"))
+                       cb.updateref = 1;
                else if (!strcmp(arg, "--all"))
                        do_all = 1;
                else if (!strcmp(arg, "--verbose"))
@@ -406,6 +433,78 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
        return status;
 }
 
+static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+               const char *email, unsigned long timestamp, int tz,
+               const char *message, void *cb_data)
+{
+       struct cmd_reflog_expire_cb *cb = cb_data;
+       if (!cb->expire_total || timestamp < cb->expire_total)
+               cb->recno++;
+       return 0;
+}
+
+static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+{
+       struct cmd_reflog_expire_cb cb;
+       int i, status = 0;
+
+       memset(&cb, 0, sizeof(cb));
+
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+               if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
+                       cb.dry_run = 1;
+               else if (!strcmp(arg, "--rewrite"))
+                       cb.rewrite = 1;
+               else if (!strcmp(arg, "--updateref"))
+                       cb.updateref = 1;
+               else if (!strcmp(arg, "--verbose"))
+                       cb.verbose = 1;
+               else if (!strcmp(arg, "--")) {
+                       i++;
+                       break;
+               }
+               else if (arg[0] == '-')
+                       usage(reflog_delete_usage);
+               else
+                       break;
+       }
+
+       if (argc - i < 1)
+               return error("Nothing to delete?");
+
+       for ( ; i < argc; i++) {
+               const char *spec = strstr(argv[i], "@{");
+               unsigned char sha1[20];
+               char *ep, *ref;
+               int recno;
+
+               if (!spec) {
+                       status |= error("Not a reflog: %s", argv[i]);
+                       continue;
+               }
+
+               if (!dwim_ref(argv[i], spec - argv[i], sha1, &ref)) {
+                       status |= error("%s points nowhere!", argv[i]);
+                       continue;
+               }
+
+               recno = strtoul(spec + 2, &ep, 10);
+               if (*ep == '}') {
+                       cb.recno = -recno;
+                       for_each_reflog_ent(ref, count_reflog_ent, &cb);
+               } else {
+                       cb.expire_total = approxidate(spec + 2);
+                       for_each_reflog_ent(ref, count_reflog_ent, &cb);
+                       cb.expire_total = 0;
+               }
+
+               status |= expire_reflog(ref, sha1, 0, &cb);
+               free(ref);
+       }
+       return status;
+}
+
 /*
  * main "reflog"
  */
@@ -425,6 +524,9 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
        if (!strcmp(argv[1], "expire"))
                return cmd_reflog_expire(argc - 1, argv + 1, prefix);
 
+       if (!strcmp(argv[1], "delete"))
+               return cmd_reflog_delete(argc - 1, argv + 1, prefix);
+
        /* Not a recognized reflog command..*/
        usage(reflog_usage);
 }
index af31abaaf862bb85a72e8052cf28a874d34c714a..b22b0edd65eefacabb648962b9c20c695609a3f5 100644 (file)
@@ -70,11 +70,12 @@ static void insert_one_record(struct shortlog *log,
        else
                free(buffer);
 
+       /* Skip any leading whitespace, including any blank lines. */
+       while (*oneline && isspace(*oneline))
+               oneline++;
        eol = strchr(oneline, '\n');
        if (!eol)
                eol = oneline + strlen(oneline);
-       while (*oneline && isspace(*oneline) && *oneline != '\n')
-               oneline++;
        if (!prefixcmp(oneline, "[PATCH")) {
                char *eob = strchr(oneline, ']');
                if (eob && (!eol || eob < eol))
index 8f70e1efc11553ce2360fab8693e2749a3fc36b4..49e6df09654f061d674f18ffcd6347f82ea644fa 100755 (executable)
@@ -506,7 +506,33 @@ _git_bisect ()
 
 _git_branch ()
 {
-       __gitcomp "$(__git_refs)"
+       local i c=1 only_local_ref="n" has_r="n"
+
+       while [ $c -lt $COMP_CWORD ]; do
+               i="${COMP_WORDS[c]}"
+               case "$i" in
+               -d|-m)  only_local_ref="y" ;;
+               -r)     has_r="y" ;;
+               esac
+               c=$((++c))
+       done
+
+       case "${COMP_WORDS[COMP_CWORD]}" in
+       --*=*)  COMPREPLY=() ;;
+       --*)
+               __gitcomp "
+                       --color --no-color --verbose --abbrev= --no-abbrev
+                       --track --no-track
+                       "
+               ;;
+       *)
+               if [ $only_local_ref = "y" -a $has_r = "n" ]; then
+                       __gitcomp "$(__git_heads)"
+               else
+                       __gitcomp "$(__git_refs)"
+               fi
+               ;;
+       esac
 }
 
 _git_bundle ()
index c9268234a5b7342849a7a711e0bb0c6e4f003754..4fa853fae76dc2ac132e489f5f1b630b3fc0f1de 100644 (file)
@@ -1299,7 +1299,7 @@ Return the list of files that haven't been handled."
   (let (author-name author-email subject date msg)
     (with-temp-buffer
       (let ((coding-system (git-get-logoutput-coding-system)))
-        (git-call-process-env t nil "log" "-1" commit)
+        (git-call-process-env t nil "log" "-1" "--pretty=medium" commit)
         (goto-char (point-min))
         (when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t)
           (setq author-name (match-string 1))
index 77c88ebf1f1029083614c2ff63011bd1b2d269fb..62a740c48248d94e1e0577c8676b13b7a726f21c 100644 (file)
@@ -567,7 +567,7 @@ generate_general_email()
        echo ""
        if [ "$newrev_type" = "commit" ]; then
                echo $LOGBEGIN
-               git show --no-color --root -s $newrev
+               git show --no-color --root -s --pretty=medium $newrev
                echo $LOGEND
        else
                # What can we do here?  The tag marks an object that is not
index 7f197d5e36ae977e21251dbb45fa72973ea7830f..655913ddb27f758ce494fc18551e852c9a6aa9f1 100644 (file)
@@ -2291,7 +2291,8 @@ static void cmd_reset_branch(void)
        else
                b = new_branch(sp);
        read_next_command();
-       if (!cmd_from(b) && command_buf.len > 0)
+       cmd_from(b);
+       if (command_buf.len > 0)
                unread_command_buf = 1;
 }
 
diff --git a/fsck.c b/fsck.c
index 6883d1bd68d158290acb18ae9b4e8baba7525201..797e3178ae279f444d2efa7e3758652ad0898dd7 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -155,8 +155,6 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        o_mode = 0;
        o_name = NULL;
        o_sha1 = NULL;
-       if (!desc.size)
-               return error_func(&item->object, FSCK_ERROR, "empty tree");
 
        while (desc.size) {
                unsigned mode;
index 2a40703c851d7011723588dd7643dc034db49c31..591244351ec4e410ea3b7f891d0de2f33a5aff7a 100644 (file)
@@ -437,4 +437,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 #define qsort git_qsort
 #endif
 
+#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
+# define FORCE_DIR_SET_GID S_ISGID
+#else
+# define FORCE_DIR_SET_GID 0
+#endif
+
 #endif
index afe3d0b7fe4d643688e672f62844cc86ec64fab5..7f632af20defd7a3cfd92008c51f7e599be13830 100755 (executable)
@@ -2556,7 +2556,7 @@ sub update
                     if ($base) {
                         my @merged;
                         # print "want to log between  $base $parent \n";
-                        open(GITLOG, '-|', 'git-log', "$base..$parent")
+                        open(GITLOG, '-|', 'git-log', '--pretty=medium', "$base..$parent")
                          or die "Cannot call git-log: $!";
                         my $mergedhash;
                         while (<GITLOG>) {
index 49e13f0bb1ed2bcb6e85455f24dffa912927d67a..010353ad82881886b9739cc5f8de595acc9273ef 100755 (executable)
@@ -252,7 +252,16 @@ while read commit parents; do
                git read-tree -i -m $commit
                ;;
        *)
-               git read-tree -i -m $commit:"$filter_subdir"
+               # The commit may not have the subdirectory at all
+               err=$(git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
+                       if ! git rev-parse --verify $commit:"$filter_subdir" 2>/dev/null
+                       then
+                               rm -f "$GIT_INDEX_FILE"
+                       else
+                               echo >&2 "$err"
+                               false
+                       fi
+               }
        esac || die "Could not initialize the index"
 
        GIT_COMMIT=$commit
index 01e0a46ba56faa8a17ed8710346b18dd215899c7..4e321742ab8f103d829f33ab4d6ab5430fa132ba 100644 (file)
@@ -224,6 +224,11 @@ else
        ifeq ($(shell $(MSGFMT) >/dev/null 2>&1 || echo $$?),127)
                MSGFMT := $(TCL_PATH) po/po2msg.sh
        endif
+       ifeq (msgfmt,$(MSGFMT))
+       ifeq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null || echo $?),1)
+               MSGFMT := $(TCL_PATH) po/po2msg.sh
+       endif
+       endif
 endif
 
 msgsdir     = $(gg_libdir)/msgs
index 03cd39873aef7b7ce00c4c2a826eab867ecc29ac..7dbbb1d79dc1d66db3a662045a13554f8d574004 100755 (executable)
@@ -71,7 +71,7 @@ finish_up_to_date () {
 squash_message () {
        echo Squashed commit of the following:
        echo
-       git log --no-merges ^"$head" $remoteheads
+       git log --no-merges --pretty=medium ^"$head" $remoteheads
 }
 
 finish () {
index cbbb707959cc64427f7bbd7bfefb0a8f0f263596..5c86f69229042c16704d11ce404e43297cc7b72c 100755 (executable)
@@ -34,7 +34,7 @@ base_present () {
 
 cleanup_temp_files () {
     if test "$1" = --save-backup ; then
-       mv -- "$BACKUP" "$path.orig"
+       mv -- "$BACKUP" "$MERGED.orig"
        rm -f -- "$LOCAL" "$REMOTE" "$BASE"
     else
        rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
@@ -67,14 +67,14 @@ resolve_symlink_merge () {
        read ans
        case "$ans" in
            [lL]*)
-               git checkout-index -f --stage=2 -- "$path"
-               git add -- "$path"
+               git checkout-index -f --stage=2 -- "$MERGED"
+               git add -- "$MERGED"
                cleanup_temp_files --save-backup
                return
                ;;
            [rR]*)
-               git checkout-index -f --stage=3 -- "$path"
-               git add -- "$path"
+               git checkout-index -f --stage=3 -- "$MERGED"
+               git add -- "$MERGED"
                cleanup_temp_files --save-backup
                return
                ;;
@@ -95,12 +95,12 @@ resolve_deleted_merge () {
        read ans
        case "$ans" in
            [mMcC]*)
-               git add -- "$path"
+               git add -- "$MERGED"
                cleanup_temp_files --save-backup
                return
                ;;
            [dD]*)
-               git rm -- "$path" > /dev/null
+               git rm -- "$MERGED" > /dev/null
                cleanup_temp_files
                return
                ;;
@@ -112,11 +112,11 @@ resolve_deleted_merge () {
 }
 
 check_unchanged () {
-    if test "$path" -nt "$BACKUP" ; then
+    if test "$MERGED" -nt "$BACKUP" ; then
        status=0;
     else
        while true; do
-           echo "$path seems unchanged."
+           echo "$MERGED seems unchanged."
            printf "Was the merge successful? [y/n] "
            read answer < /dev/tty
            case "$answer" in
@@ -127,50 +127,38 @@ check_unchanged () {
     fi
 }
 
-save_backup () {
-    if test "$status" -eq 0; then
-       mv -- "$BACKUP" "$path.orig"
-    fi
-}
-
-remove_backup () {
-    if test "$status" -eq 0; then
-       rm "$BACKUP"
-    fi
-}
-
 merge_file () {
-    path="$1"
+    MERGED="$1"
 
-    f=`git ls-files -u -- "$path"`
+    f=`git ls-files -u -- "$MERGED"`
     if test -z "$f" ; then
-       if test ! -f "$path" ; then
-           echo "$path: file not found"
+       if test ! -f "$MERGED" ; then
+           echo "$MERGED: file not found"
        else
-           echo "$path: file does not need merging"
+           echo "$MERGED: file does not need merging"
        fi
        exit 1
     fi
 
-    ext="$$$(expr "$path" : '.*\(\.[^/]*\)$')"
-    BACKUP="$path.BACKUP.$ext"
-    LOCAL="$path.LOCAL.$ext"
-    REMOTE="$path.REMOTE.$ext"
-    BASE="$path.BASE.$ext"
+    ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
+    BACKUP="$MERGED.BACKUP.$ext"
+    LOCAL="$MERGED.LOCAL.$ext"
+    REMOTE="$MERGED.REMOTE.$ext"
+    BASE="$MERGED.BASE.$ext"
 
-    mv -- "$path" "$BACKUP"
-    cp -- "$BACKUP" "$path"
+    mv -- "$MERGED" "$BACKUP"
+    cp -- "$BACKUP" "$MERGED"
 
-    base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'`
-    local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'`
-    remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'`
+    base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'`
+    local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
+    remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
 
-    base_present   && git cat-file blob ":1:$prefix$path" >"$BASE" 2>/dev/null
-    local_present  && git cat-file blob ":2:$prefix$path" >"$LOCAL" 2>/dev/null
-    remote_present && git cat-file blob ":3:$prefix$path" >"$REMOTE" 2>/dev/null
+    base_present   && git cat-file blob ":1:$prefix$MERGED" >"$BASE" 2>/dev/null
+    local_present  && git cat-file blob ":2:$prefix$MERGED" >"$LOCAL" 2>/dev/null
+    remote_present && git cat-file blob ":3:$prefix$MERGED" >"$REMOTE" 2>/dev/null
 
     if test -z "$local_mode" -o -z "$remote_mode"; then
-       echo "Deleted merge conflict for '$path':"
+       echo "Deleted merge conflict for '$MERGED':"
        describe_file "$local_mode" "local" "$LOCAL"
        describe_file "$remote_mode" "remote" "$REMOTE"
        resolve_deleted_merge
@@ -178,14 +166,14 @@ merge_file () {
     fi
 
     if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
-       echo "Symbolic link merge conflict for '$path':"
+       echo "Symbolic link merge conflict for '$MERGED':"
        describe_file "$local_mode" "local" "$LOCAL"
        describe_file "$remote_mode" "remote" "$REMOTE"
        resolve_symlink_merge
        return
     fi
 
-    echo "Normal merge conflict for '$path':"
+    echo "Normal merge conflict for '$MERGED':"
     describe_file "$local_mode" "local" "$LOCAL"
     describe_file "$remote_mode" "remote" "$REMOTE"
     printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
@@ -194,36 +182,32 @@ merge_file () {
     case "$merge_tool" in
        kdiff3)
            if base_present ; then
-               ("$merge_tool_path" --auto --L1 "$path (Base)" --L2 "$path (Local)" --L3 "$path (Remote)" \
-                   -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+               ("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \
+                   -o "$MERGED" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
            else
-               ("$merge_tool_path" --auto --L1 "$path (Local)" --L2 "$path (Remote)" \
-                   -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+               ("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \
+                   -o "$MERGED" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
            fi
            status=$?
-           remove_backup
            ;;
        tkdiff)
            if base_present ; then
-               "$merge_tool_path" -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE"
+               "$merge_tool_path" -a "$BASE" -o "$MERGED" -- "$LOCAL" "$REMOTE"
            else
-               "$merge_tool_path" -o "$path" -- "$LOCAL" "$REMOTE"
+               "$merge_tool_path" -o "$MERGED" -- "$LOCAL" "$REMOTE"
            fi
            status=$?
-           save_backup
            ;;
        meld|vimdiff)
            touch "$BACKUP"
-           "$merge_tool_path" -- "$LOCAL" "$path" "$REMOTE"
+           "$merge_tool_path" -- "$LOCAL" "$MERGED" "$REMOTE"
            check_unchanged
-           save_backup
            ;;
        gvimdiff)
-               touch "$BACKUP"
-               "$merge_tool_path" -f -- "$LOCAL" "$path" "$REMOTE"
-               check_unchanged
-               save_backup
-               ;;
+           touch "$BACKUP"
+           "$merge_tool_path" -f -- "$LOCAL" "$MERGED" "$REMOTE"
+           check_unchanged
+           ;;
        xxdiff)
            touch "$BACKUP"
            if base_present ; then
@@ -231,53 +215,68 @@ merge_file () {
                    -R 'Accel.SaveAsMerged: "Ctrl-S"' \
                    -R 'Accel.Search: "Ctrl+F"' \
                    -R 'Accel.SearchForward: "Ctrl-G"' \
-                   --merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE"
+                   --merged-file "$MERGED" -- "$LOCAL" "$BASE" "$REMOTE"
            else
                "$merge_tool_path" -X --show-merged-pane \
                    -R 'Accel.SaveAsMerged: "Ctrl-S"' \
                    -R 'Accel.Search: "Ctrl+F"' \
                    -R 'Accel.SearchForward: "Ctrl-G"' \
-                   --merged-file "$path" -- "$LOCAL" "$REMOTE"
+                   --merged-file "$MERGED" -- "$LOCAL" "$REMOTE"
            fi
            check_unchanged
-           save_backup
            ;;
        opendiff)
            touch "$BACKUP"
            if base_present; then
-               "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$path" | cat
+               "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat
            else
-               "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$path" | cat
+               "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat
            fi
            check_unchanged
-           save_backup
            ;;
        ecmerge)
            touch "$BACKUP"
            if base_present; then
-               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --mode=merge3 --to="$path"
+               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --mode=merge3 --to="$MERGED"
            else
-               "$merge_tool_path" "$LOCAL" "$REMOTE" --mode=merge2 --to="$path"
+               "$merge_tool_path" "$LOCAL" "$REMOTE" --mode=merge2 --to="$MERGED"
            fi
            check_unchanged
-           save_backup
            ;;
        emerge)
            if base_present ; then
-               "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$path")"
+               "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")"
            else
-               "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$path")"
+               "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
            fi
            status=$?
-           save_backup
+           ;;
+       *)
+           if test -n "$merge_tool_cmd"; then
+               if test "$merge_tool_trust_exit_code" = "false"; then
+                   touch "$BACKUP"
+                   ( eval $merge_tool_cmd )
+                   check_unchanged
+               else
+                   ( eval $merge_tool_cmd )
+                   status=$?
+               fi
+           fi
            ;;
     esac
     if test "$status" -ne 0; then
-       echo "merge of $path failed" 1>&2
-       mv -- "$BACKUP" "$path"
+       echo "merge of $MERGED failed" 1>&2
+       mv -- "$BACKUP" "$MERGED"
        exit 1
     fi
-    git add -- "$path"
+
+    if test "$merge_keep_backup" = "true"; then
+       mv -- "$BACKUP" "$MERGED.orig"
+    else
+       rm -- "$BACKUP"
+    fi
+
+    git add -- "$MERGED"
     cleanup_temp_files
 }
 
@@ -309,12 +308,20 @@ do
     shift
 done
 
+valid_custom_tool()
+{
+    merge_tool_cmd="$(git config mergetool.$1.cmd)"
+    test -n "$merge_tool_cmd"
+}
+
 valid_tool() {
        case "$1" in
                kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
                        ;; # happy
                *)
-                       return 1
+                       if ! valid_custom_tool "$1"; then
+                               return 1
+                       fi
                        ;;
        esac
 }
@@ -380,10 +387,16 @@ else
 
     init_merge_tool_path "$merge_tool"
 
-    if ! type "$merge_tool_path" > /dev/null 2>&1; then
+    merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
+
+    if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
         echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
         exit 1
     fi
+
+    if ! test -z "$merge_tool_cmd"; then
+        merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
+    fi
 fi
 
 
index 29b1105c4c3c83258ebdf53c8885f767baa0ace0..be4a20d7cd562e9b00d93fe71313aed70afe50af 100755 (executable)
@@ -317,7 +317,7 @@ if ($suppress_cc{'all'}) {
 
 # If explicit old-style ones are specified, they trump --suppress-cc.
 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
-$suppress_cc{'sob'} = $signed_off_cc if defined $signed_off_cc;
+$suppress_cc{'sob'} = !$signed_off_cc if defined $signed_off_cc;
 
 # Debugging, print out the suppressions.
 if (0) {
@@ -855,6 +855,7 @@ foreach my $t (@files) {
                        $message .=  $_;
                        if (/^(Signed-off-by|Cc): (.*)$/i) {
                                next if ($suppress_cc{'sob'});
+                               chomp;
                                my $c = $2;
                                chomp $c;
                                next if ($c eq $sender and $suppress_cc{'self'});
index b00f8881693ff09516ea058816dc96697ca56483..c2b68205a2b69eb91b2403e11238093fc65c04ef 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # Copyright (c) 2007, Nanako Shiraishi
 
-USAGE='[  | save | list | show | apply | clear | create ]'
+USAGE='[  | save | list | show | apply | clear | drop | pop | create ]'
 
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
@@ -196,6 +196,28 @@ apply_stash () {
        fi
 }
 
+drop_stash () {
+       have_stash || die 'No stash entries to drop'
+
+       if test $# = 0
+       then
+               set x "$ref_stash@{0}"
+               shift
+       fi
+       # Verify supplied argument looks like a stash entry
+       s=$(git rev-parse --revs-only --no-flags "$@") &&
+       git rev-parse --verify "$s:"   > /dev/null 2>&1 &&
+       git rev-parse --verify "$s^1:" > /dev/null 2>&1 &&
+       git rev-parse --verify "$s^2:" > /dev/null 2>&1 ||
+               die "$*: not a valid stashed state"
+
+       git reflog delete --updateref --rewrite "$@" &&
+               echo "Dropped $* ($s)" || die "$*: Could not drop stash entry"
+
+       # clear_stash if we just dropped the last stash entry
+       git rev-parse --verify "$ref_stash@{0}" > /dev/null 2>&1 || clear_stash
+}
+
 # Main command set
 case "$1" in
 list)
@@ -230,6 +252,18 @@ create)
        fi
        create_stash "$*" && echo "$w_commit"
        ;;
+drop)
+       shift
+       drop_stash "$@"
+       ;;
+pop)
+       shift
+       if apply_stash "$@"
+       then
+               test -z "$unstash_index" || shift
+               drop_stash "$@"
+       fi
+       ;;
 *)
        if test $# -eq 0
        then
index 9e2faf90aa1676974234882a2f557c17f7bc59f4..1195569529401fd1c62414c8683a6b577721c1c7 100755 (executable)
@@ -1540,9 +1540,14 @@ sub find_by_url { # repos_root and, path are optional
                                            $remotes->{$repo_id}->{$_});
                }
                my $p = $path;
+               my $rwr = rewrite_root({repo_id => $repo_id});
                unless (defined $p) {
                        $p = $full_url;
-                       $p =~ s#^\Q$u\E(?:/|$)## or next;
+                       my $z = $u;
+                       if ($rwr) {
+                               $z = $rwr;
+                       }
+                       $p =~ s#^\Q$z\E(?:/|$)## or next;
                }
                foreach my $f (keys %$fetch) {
                        next if $f ne $p;
index 922dee98b91132b4a4aca37a382ae7c9711aa2e8..ec73cb1256ba99a990648c548348ecdc3340a592 100755 (executable)
@@ -5305,51 +5305,19 @@ sub git_search {
                print "<table class=\"pickaxe search\">\n";
                my $alternate = 1;
                $/ = "\n";
-               my $git_command = git_cmd_str();
-               my $searchqtext = $searchtext;
-               $searchqtext =~ s/'/'\\''/;
-               my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : '';
-               open my $fd, "-|", "$git_command rev-list $hash | " .
-                       "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags";
+               open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,
+                       '--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext",
+                       ($search_use_regexp ? '--pickaxe-regex' : ());
                undef %co;
                my @files;
                while (my $line = <$fd>) {
-                       if (%co && $line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)\t(.*)$/) {
-                               my %set;
-                               $set{'file'} = $6;
-                               $set{'from_id'} = $3;
-                               $set{'to_id'} = $4;
-                               $set{'id'} = $set{'to_id'};
-                               if ($set{'id'} =~ m/0{40}/) {
-                                       $set{'id'} = $set{'from_id'};
-                               }
-                               if ($set{'id'} =~ m/0{40}/) {
-                                       next;
-                               }
-                               push @files, \%set;
-                       } elsif ($line =~ m/^([0-9a-fA-F]{40})$/){
+                       chomp $line;
+                       next unless $line;
+
+                       my %set = parse_difftree_raw_line($line);
+                       if (defined $set{'commit'}) {
+                               # finish previous commit
                                if (%co) {
-                                       if ($alternate) {
-                                               print "<tr class=\"dark\">\n";
-                                       } else {
-                                               print "<tr class=\"light\">\n";
-                                       }
-                                       $alternate ^= 1;
-                                       my $author = chop_and_escape_str($co{'author_name'}, 15, 5);
-                                       print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
-                                             "<td><i>" . $author . "</i></td>\n" .
-                                             "<td>" .
-                                             $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
-                                                     -class => "list subject"},
-                                                     chop_and_escape_str($co{'title'}, 50) . "<br/>");
-                                       while (my $setref = shift @files) {
-                                               my %set = %$setref;
-                                               print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
-                                                                            hash=>$set{'id'}, file_name=>$set{'file'}),
-                                                             -class => "list"},
-                                                             "<span class=\"match\">" . esc_path($set{'file'}) . "</span>") .
-                                                     "<br/>\n";
-                                       }
                                        print "</td>\n" .
                                              "<td class=\"link\">" .
                                              $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") .
@@ -5358,11 +5326,44 @@ sub git_search {
                                        print "</td>\n" .
                                              "</tr>\n";
                                }
-                               %co = parse_commit($1);
+
+                               if ($alternate) {
+                                       print "<tr class=\"dark\">\n";
+                               } else {
+                                       print "<tr class=\"light\">\n";
+                               }
+                               $alternate ^= 1;
+                               %co = parse_commit($set{'commit'});
+                               my $author = chop_and_escape_str($co{'author_name'}, 15, 5);
+                               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+                                     "<td><i>$author</i></td>\n" .
+                                     "<td>" .
+                                     $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
+                                             -class => "list subject"},
+                                             chop_and_escape_str($co{'title'}, 50) . "<br/>");
+                       } elsif (defined $set{'to_id'}) {
+                               next if ($set{'to_id'} =~ m/^0{40}$/);
+
+                               print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
+                                                            hash=>$set{'to_id'}, file_name=>$set{'to_file'}),
+                                             -class => "list"},
+                                             "<span class=\"match\">" . esc_path($set{'file'}) . "</span>") .
+                                     "<br/>\n";
                        }
                }
                close $fd;
 
+               # finish last commit (warning: repetition!)
+               if (%co) {
+                       print "</td>\n" .
+                             "<td class=\"link\">" .
+                             $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") .
+                             " | " .
+                             $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree");
+                       print "</td>\n" .
+                             "</tr>\n";
+               }
+
                print "</table>\n";
        }
 
diff --git a/ident.c b/ident.c
index b839dcf5f085a94080e1f7891f3fb40ed151a394..ed44a5345a47d4843e8328c0f879ac925dde2b07 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -171,7 +171,7 @@ static const char au_env[] = "GIT_AUTHOR_NAME";
 static const char co_env[] = "GIT_COMMITTER_NAME";
 static const char *env_hint =
 "\n"
-"*** Your name cannot be determined from your system services (gecos).\n"
+"*** Please tell me who you are.\n"
 "\n"
 "Run\n"
 "\n"
diff --git a/path.c b/path.c
index af2716199b92e920df9fe2021035d319e8cafbc6..f4ed979997b6a968ba1987a199beae39035d5da2 100644 (file)
--- a/path.c
+++ b/path.c
@@ -283,7 +283,7 @@ int adjust_shared_perm(const char *path)
                            ? (S_IXGRP|S_IXOTH)
                            : 0));
        if (S_ISDIR(mode))
-               mode |= S_ISGID;
+               mode |= FORCE_DIR_SET_GID;
        if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
                return -2;
        return 0;
diff --git a/quote.c b/quote.c
index d061626c34f1e62c538db6e931c29751be4fdbcf..40702f6b725efade3e1fd61339421940f9fdb47d 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -288,7 +288,7 @@ int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
                switch (*quoted++) {
                  case '"':
                        if (endp)
-                               *endp = quoted + 1;
+                               *endp = quoted;
                        return 0;
                  case '\\':
                        break;
diff --git a/refs.c b/refs.c
index c979fb1d9507309785909a8d714ab28b1efd2e88..1b0050eee4e037aec8396edd0ff6c14bda5985a2 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1033,7 +1033,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
        return 1;
 }
 
-static int close_ref(struct ref_lock *lock)
+int close_ref(struct ref_lock *lock)
 {
        if (close_lock_file(lock->lk))
                return -1;
@@ -1041,7 +1041,7 @@ static int close_ref(struct ref_lock *lock)
        return 0;
 }
 
-static int commit_ref(struct ref_lock *lock)
+int commit_ref(struct ref_lock *lock)
 {
        if (commit_lock_file(lock->lk))
                return -1;
diff --git a/refs.h b/refs.h
index 9cd16f82956d89f2800827046151abd7866fb9da..06abee15266cc3b234ec64cd27362c482874e54b 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -33,6 +33,12 @@ extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_
 #define REF_NODEREF    0x01
 extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags);
 
+/** Close the file descriptor owned by a lock and return the status */
+extern int close_ref(struct ref_lock *lock);
+
+/** Close and commit the ref locked by the lock */
+extern int commit_ref(struct ref_lock *lock);
+
 /** Release any lock taken but not written. **/
 extern void unlock_ref(struct ref_lock *lock);
 
index 743757c36ec0e5667fd8af28800ac095f1581adb..44100a749b09439121073e32e7a3143b54185d31 100644 (file)
@@ -91,6 +91,13 @@ int start_command(struct child_process *cmd)
                        close(cmd->in);
                }
 
+               if (cmd->no_stderr)
+                       dup_devnull(2);
+               else if (need_err) {
+                       dup2(fderr[1], 2);
+                       close_pair(fderr);
+               }
+
                if (cmd->no_stdout)
                        dup_devnull(1);
                else if (cmd->stdout_to_stderr)
@@ -103,13 +110,6 @@ int start_command(struct child_process *cmd)
                        close(cmd->out);
                }
 
-               if (cmd->no_stderr)
-                       dup_devnull(2);
-               else if (need_err) {
-                       dup2(fderr[1], 2);
-                       close_pair(fderr);
-               }
-
                if (cmd->dir && chdir(cmd->dir))
                        die("exec %s: cd to %s failed (%s)", cmd->argv[0],
                            cmd->dir, strerror(errno));
index f959aae84630ddbb68304868b1a025b7c2d33d10..24476bede5ce8f8720bf3d9eba7f7a944182dbf4 100755 (executable)
@@ -175,6 +175,33 @@ test_expect_success 'recover and check' '
 
 '
 
+test_expect_success 'delete' '
+       echo 1 > C &&
+       test_tick &&
+       git commit -m rat C &&
+
+       echo 2 > C &&
+       test_tick &&
+       git commit -m ox C &&
+
+       echo 3 > C &&
+       test_tick &&
+       git commit -m tiger C &&
+
+       test 5 = $(git reflog | wc -l) &&
+
+       git reflog delete master@{1} &&
+       git reflog show master > output &&
+       test 4 = $(wc -l < output) &&
+       ! grep ox < output &&
+
+       git reflog delete master@{07.04.2005.15:15:00.-0700} &&
+       git reflog show master > output &&
+       test 3 = $(wc -l < output) &&
+       ! grep dragon < output
+
+'
+
 test_expect_success 'prune --expire' '
 
        before=$(git count-objects | sed "s/ .*//") &&
index 9a9a250d2c6bad80745b7ebd2df7ac947d30b521..aa282e1bc1e17f08dd12fc1980187c786f1de99b 100755 (executable)
@@ -40,8 +40,8 @@ test_expect_success 'parents of stash' '
 test_expect_success 'apply needs clean working directory' '
        echo 4 > other-file &&
        git add other-file &&
-       echo 5 > other-file
-       ! git stash apply
+       echo 5 > other-file &&
+       test_must_fail git stash apply
 '
 
 test_expect_success 'apply stashed changes' '
@@ -70,7 +70,51 @@ test_expect_success 'unstashing in a subdirectory' '
        git reset --hard HEAD &&
        mkdir subdir &&
        cd subdir &&
-       git stash apply
+       git stash apply &&
+       cd ..
+'
+
+test_expect_success 'drop top stash' '
+       git reset --hard &&
+       git stash list > stashlist1 &&
+       echo 7 > file &&
+       git stash &&
+       git stash drop &&
+       git stash list > stashlist2 &&
+       diff stashlist1 stashlist2 &&
+       git stash apply &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_expect_success 'drop middle stash' '
+       git reset --hard &&
+       echo 8 > file &&
+       git stash &&
+       echo 9 > file &&
+       git stash &&
+       git stash drop stash@{1} &&
+       test 2 = $(git stash list | wc -l) &&
+       git stash apply &&
+       test 9 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file) &&
+       git reset --hard &&
+       git stash drop &&
+       git stash apply &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_expect_success 'stash pop' '
+       git reset --hard &&
+       git stash pop &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file) &&
+       test 0 = $(git stash list | wc -l)
 '
 
 test_done
index 868babc4b2350526192a8df53f6cbec3f81c644e..6e14bf1c7f0991bbaab217e8a08bae0cacfe1ab1 100755 (executable)
@@ -179,4 +179,28 @@ test_expect_success 'Name needing quotes' '
 
 '
 
+test_expect_success 'Subdirectory filter with disappearing trees' '
+       git reset --hard &&
+       git checkout master &&
+
+       mkdir foo &&
+       touch foo/bar &&
+       git add foo &&
+       test_tick &&
+       git commit -m "Adding foo" &&
+
+       git rm -r foo &&
+       test_tick &&
+       git commit -m "Removing foo" &&
+
+       mkdir foo &&
+       touch foo/bar &&
+       git add foo &&
+       test_tick &&
+       git commit -m "Re-adding foo" &&
+
+       git filter-branch -f --subdirectory-filter foo &&
+       test $(git rev-list master | wc -l) = 3
+'
+
 test_done
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
new file mode 100644 (file)
index 0000000..6b0483f
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Charles Bailey
+#
+
+test_description='git-mergetool
+
+Testing basic merge tool invocation'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+    echo master >file1 &&
+    git add file1 &&
+    git commit -m "added file1" &&
+    git checkout -b branch1 master &&
+    echo branch1 change >file1 &&
+    echo branch1 newfile >file2 &&
+    git add file1 file2 &&
+    git commit -m "branch1 changes" &&
+    git checkout -b branch2 master &&
+    echo branch2 change >file1 &&
+    echo branch2 newfile >file2 &&
+    git add file1 file2 &&
+    git commit -m "branch2 changes" &&
+    git checkout master &&
+    echo master updated >file1 &&
+    echo master new >file2 &&
+    git add file1 file2 &&
+    git commit -m "master updates"
+'
+
+test_expect_success 'custom mergetool' '
+    git config merge.tool mytool &&
+    git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
+    git config mergetool.mytool.trustExitCode true &&
+       git checkout branch1 &&
+    ! git merge master >/dev/null 2>&1 &&
+    ( yes "" | git mergetool file1>/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool file2>/dev/null 2>&1 ) &&
+    test "$(cat file1)" = "master updated" &&
+    test "$(cat file2)" = "master new" &&
+       git commit -m "branch1 resolved with mergetool"
+'
+
+test_done
index cceedbb2b7efc20b79155889ed20c5a7866fed9c..c4f4465dc687d30138a9111ae2efbc0e3aaf42b6 100755 (executable)
@@ -869,6 +869,8 @@ zcommits
 COMMIT
 reset refs/tags/O3-2nd
 from :5
+reset refs/tags/O3-3rd
+from :5
 INPUT_END
 
 cat >expect <<INPUT_END
index 87a5ea4a6a54d712c0973cd9b8090c3ec83fb828..6aea0ea0a579973c9baddff608ea92445ef9fcbb 100644 (file)
@@ -3,12 +3,16 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
+# Keep the original TERM for say_color
+ORIGINAL_TERM=$TERM
+
 # For repeatability, reset the environment to known value.
 LANG=C
 LC_ALL=C
 PAGER=cat
 TZ=UTC
-export LANG LC_ALL PAGER TZ
+TERM=dumb
+export LANG LC_ALL PAGER TERM TZ
 EDITOR=:
 VISUAL=:
 unset GIT_EDITOR
@@ -58,12 +62,14 @@ esac
 # This test checks if command xyzzy does the right thing...
 # '
 # . ./test-lib.sh
-
-[ "x$TERM" != "xdumb" ] &&
-       [ -t 1 ] &&
-       tput bold >/dev/null 2>&1 &&
-       tput setaf 1 >/dev/null 2>&1 &&
-       tput sgr0 >/dev/null 2>&1 &&
+[ "x$ORIGINAL_TERM" != "xdumb" ] && (
+               TERM=$ORIGINAL_TERM &&
+               export TERM &&
+               [ -t 1 ] &&
+               tput bold >/dev/null 2>&1 &&
+               tput setaf 1 >/dev/null 2>&1 &&
+               tput sgr0 >/dev/null 2>&1
+       ) &&
        color=t
 
 while test "$#" -ne 0
@@ -91,6 +97,9 @@ done
 
 if test -n "$color"; then
        say_color () {
+               (
+               TERM=$ORIGINAL_TERM
+               export TERM
                case "$1" in
                        error) tput bold; tput setaf 1;; # bold red
                        skip)  tput bold; tput setaf 2;; # bold green
@@ -101,6 +110,7 @@ if test -n "$color"; then
                shift
                echo "* $*"
                tput sgr0
+               )
        }
 else
        say_color() {