summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.5.4.4.txt32
-rw-r--r--Documentation/RelNotes-1.5.5.txt4
-rw-r--r--Documentation/config.txt44
-rw-r--r--Documentation/git-mergetool.txt38
-rw-r--r--Documentation/git-reflog.txt14
-rw-r--r--Documentation/git-stash.txt13
-rw-r--r--Documentation/git-whatchanged.txt9
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/pretty-options.txt3
-rw-r--r--Documentation/technical/api-run-command.txt7
-rw-r--r--Makefile4
-rw-r--r--builtin-log.c5
-rw-r--r--builtin-reflog.c102
-rw-r--r--builtin-reset.c47
-rw-r--r--builtin-shortlog.c5
-rwxr-xr-xcontrib/completion/git-completion.bash28
-rw-r--r--contrib/emacs/git.el2
-rw-r--r--contrib/hooks/post-receive-email2
-rw-r--r--fast-import.c3
-rw-r--r--git-compat-util.h6
-rwxr-xr-xgit-cvsserver.perl2
-rwxr-xr-xgit-filter-branch.sh11
-rw-r--r--git-gui/Makefile5
-rwxr-xr-xgit-merge.sh2
-rwxr-xr-xgit-mergetool.sh161
-rwxr-xr-xgit-send-email.perl3
-rwxr-xr-xgit-stash.sh36
-rwxr-xr-xgit-svn.perl7
-rwxr-xr-xgitweb/gitweb.perl85
-rw-r--r--ident.c2
-rw-r--r--path.c2
-rw-r--r--quote.c2
-rw-r--r--refs.c4
-rw-r--r--refs.h6
-rw-r--r--run-command.c14
-rwxr-xr-xt/t1410-reflog.sh27
-rwxr-xr-xt/t3903-stash.sh50
-rwxr-xr-xt/t7003-filter-branch.sh24
-rw-r--r--t/t7610-mergetool.sh46
-rwxr-xr-xt/t9300-fast-import.sh2
-rw-r--r--t/test-lib.sh24
41 files changed, 675 insertions, 211 deletions
diff --git a/Documentation/RelNotes-1.5.4.4.txt b/Documentation/RelNotes-1.5.4.4.txt
index 5635977c93..89fa6d03bc 100644
--- a/Documentation/RelNotes-1.5.4.4.txt
+++ b/Documentation/RelNotes-1.5.4.4.txt
@@ -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.
diff --git a/Documentation/RelNotes-1.5.5.txt b/Documentation/RelNotes-1.5.5.txt
index b57fa1eb1a..874dad9a4f 100644
--- a/Documentation/RelNotes-1.5.5.txt
+++ b/Documentation/RelNotes-1.5.5.txt
@@ -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.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4027726f2e..c5e094a9c4 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -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
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index 50f106ec5b..8ed44947ef 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -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
------
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index f9bba36c23..047e3ce14d 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -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.
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 48e6f5a3f7..8dc35d493e 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -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
----------
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 54947b6769..a6e7bd4c8b 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -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::
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 741ae0e4c8..3ed24d449a 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.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],
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 973d8dd733..6d66c74cc1 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -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
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index fde3b45321..c364a22c8f 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -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:
diff --git a/Makefile b/Makefile
index ca5aad963c..6e857e62c3 100644
--- 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
diff --git a/builtin-log.c b/builtin-log.c
index fe8fc6f22a..d983cbc7bc 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -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);
diff --git a/builtin-reflog.c b/builtin-reflog.c
index ab53c8cb7c..280e24e151 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -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);
}
diff --git a/builtin-reset.c b/builtin-reset.c
index bb3e19240a..79424bb26e 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -17,9 +17,13 @@
#include "diffcore.h"
#include "tree.h"
#include "branch.h"
+#include "parse-options.h"
-static const char builtin_reset_usage[] =
-"git-reset [--mixed | --soft | --hard] [-q] [<commit-ish>] [ [--] <paths>...]";
+static const char * const git_reset_usage[] = {
+ "git-reset [--mixed | --soft | --hard] [-q] [<commit>]",
+ "git-reset [--mixed] <commit> [--] <paths>...",
+ NULL
+};
static char *args_to_str(const char **argv)
{
@@ -165,40 +169,31 @@ static const char *reset_type_names[] = { "mixed", "soft", "hard", NULL };
int cmd_reset(int argc, const char **argv, const char *prefix)
{
- int i = 1, reset_type = NONE, update_ref_status = 0, quiet = 0;
+ int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
const char *rev = "HEAD";
unsigned char sha1[20], *orig = NULL, sha1_orig[20],
*old_orig = NULL, sha1_old_orig[20];
struct commit *commit;
char *reflog_action, msg[1024];
+ const struct option options[] = {
+ OPT_SET_INT(0, "mixed", &reset_type,
+ "reset HEAD and index", MIXED),
+ OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
+ OPT_SET_INT(0, "hard", &reset_type,
+ "reset HEAD, index and working tree", HARD),
+ OPT_BOOLEAN('q', NULL, &quiet,
+ "disable showing new HEAD in hard reset"),
+ OPT_END()
+ };
git_config(git_default_config);
+ argc = parse_options(argc, argv, options, git_reset_usage,
+ PARSE_OPT_KEEP_DASHDASH);
reflog_action = args_to_str(argv);
setenv("GIT_REFLOG_ACTION", reflog_action, 0);
- while (i < argc) {
- if (!strcmp(argv[i], "--mixed")) {
- reset_type = MIXED;
- i++;
- }
- else if (!strcmp(argv[i], "--soft")) {
- reset_type = SOFT;
- i++;
- }
- else if (!strcmp(argv[i], "--hard")) {
- reset_type = HARD;
- i++;
- }
- else if (!strcmp(argv[i], "-q")) {
- quiet = 1;
- i++;
- }
- else
- break;
- }
-
- if (i < argc && argv[i][0] != '-')
+ if (i < argc && strcmp(argv[i], "--"))
rev = argv[i++];
if (get_sha1(rev, sha1))
@@ -211,8 +206,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (i < argc && !strcmp(argv[i], "--"))
i++;
- else if (i < argc && argv[i][0] == '-')
- usage(builtin_reset_usage);
/* git reset tree [--] paths... can be used to
* load chosen paths from the tree into the index without
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index af31abaaf8..b22b0edd65 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -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))
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 5ae87998e6..848c067b57 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -514,7 +514,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 ()
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index c9268234a5..4fa853fae7 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -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))
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 77c88ebf1f..62a740c482 100644
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -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
diff --git a/fast-import.c b/fast-import.c
index 7f197d5e36..655913ddb2 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -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/git-compat-util.h b/git-compat-util.h
index 2a40703c85..591244351e 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -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
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index afe3d0b7fe..7f632af20d 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -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>) {
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 49e13f0bb1..010353ad82 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -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
diff --git a/git-gui/Makefile b/git-gui/Makefile
index 01e0a46ba5..4e321742ab 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -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
diff --git a/git-merge.sh b/git-merge.sh
index 03cd39873a..7dbbb1d79d 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -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 () {
diff --git a/git-mergetool.sh b/git-mergetool.sh
index cbbb707959..5c86f69229 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -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
diff --git a/git-send-email.perl b/git-send-email.perl
index 29b1105c4c..be4a20d7cd 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -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'});
diff --git a/git-stash.sh b/git-stash.sh
index b00f888169..c2b68205a2 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -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
diff --git a/git-svn.perl b/git-svn.perl
index 9e2faf90aa..1195569529 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -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;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 922dee98b9..ec73cb1256 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -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 b839dcf5f0..ed44a5345a 100644
--- 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 af2716199b..f4ed979997 100644
--- 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 d061626c34..40702f6b72 100644
--- 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 c979fb1d95..1b0050eee4 100644
--- 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 9cd16f8295..06abee1526 100644
--- 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);
diff --git a/run-command.c b/run-command.c
index 743757c36e..44100a749b 100644
--- a/run-command.c
+++ b/run-command.c
@@ -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));
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index f959aae846..24476bede5 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -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/ .*//") &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 9a9a250d2c..aa282e1bc1 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 868babc4b2..6e14bf1c7f 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -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
index 0000000000..6b0483f3e9
--- /dev/null
+++ b/t/t7610-mergetool.sh
@@ -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
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index cceedbb2b7..c4f4465dc6 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -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
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 87a5ea4a6a..6aea0ea0a5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -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() {