diff options
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: @@ -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"; } @@ -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" @@ -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; @@ -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; @@ -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; @@ -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() { |