diff options
55 files changed, 548 insertions, 331 deletions
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 8601949e80..90722c21fa 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -49,7 +49,7 @@ People on the git mailing list need to be able to read and comment on the changes you are submitting. It is important for a developer to be able to "quote" your changes, using standard e-mail tools, so that they may comment on specific portions of -your code. For this reason, all patches should be submited +your code. For this reason, all patches should be submitted "inline". WARNING: Be wary of your MUAs word-wrap corrupting your patch. Do not cut-n-paste your patch; you can lose tabs that way if you are not careful. diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index 1fbca83141..d2b0bd38de 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -93,7 +93,7 @@ machine where the repository is hosted. If you don't want to give them a full shell on the machine, there is a restricted shell which only allows users to do git pushes and pulls; see gitlink:git-shell[1]. -Put all the committers should in the same group, and make the repository +Put all the committers in the same group, and make the repository writable by that group: ------------------------------------------------ diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index f523ec2fbe..1a936295d8 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -94,5 +94,11 @@ Swap two inputs; that is, show differences from index or on-disk file to tree contents. +--text:: + Treat all files as text. + +-a:: + Shorthand for "--text". + For more detailed explanation on these common options, see also link:diffcore.html[diffcore documentation]. diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt index 56bd3e517d..27ac72d98f 100644 --- a/Documentation/git-cvsexportcommit.txt +++ b/Documentation/git-cvsexportcommit.txt @@ -8,7 +8,7 @@ git-cvsexportcommit - Export a commit to a CVS checkout SYNOPSIS -------- -'git-cvsexportcommmit' [-h] [-v] [-c] [-p] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID +'git-cvsexportcommit' [-h] [-v] [-c] [-p] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID DESCRIPTION diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt index 481b8b3aa0..7248b35d95 100644 --- a/Documentation/git-diff-files.txt +++ b/Documentation/git-diff-files.txt @@ -37,7 +37,7 @@ omit diff output for unmerged entries and just show "Unmerged". commit with these flags. -q:: - Remain silent even on nonexisting files + Remain silent even on nonexistent files Output format ------------- diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index 7ab2080376..228c4d95bd 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -8,24 +8,24 @@ git-diff - Show changes between commits, commit and working tree, etc SYNOPSIS -------- -'git-diff' [ --diff-options ] <ent>{0,2} [<path>...] +'git-diff' [ --diff-options ] <tree-ish>{0,2} [<path>...] DESCRIPTION ----------- -Show changes between two ents, an ent and the working tree, an -ent and the index file, or the index file and the working tree. +Show changes between two trees, a tree and the working tree, a +tree and the index file, or the index file and the working tree. The combination of what is compared with what is determined by -the number of ents given to the command. +the number of trees given to the command. -* When no <ent> is given, the working tree and the index - file is compared, using `git-diff-files`. +* When no <tree-ish> is given, the working tree and the index + file are compared, using `git-diff-files`. -* When one <ent> is given, the working tree and the named - tree is compared, using `git-diff-index`. The option +* When one <tree-ish> is given, the working tree and the named + tree are compared, using `git-diff-index`. The option `--cached` can be given to compare the index file and the named tree. -* When two <ent>s are given, these two trees are compared +* When two <tree-ish>s are given, these two trees are compared using `git-diff-tree`. OPTIONS diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt index 8a150d861f..0a4fc14b97 100644 --- a/Documentation/git-init-db.txt +++ b/Documentation/git-init-db.txt @@ -25,7 +25,7 @@ DESCRIPTION ----------- This command creates an empty git repository - basically a `.git` directory with subdirectories for `objects`, `refs/heads`, `refs/tags`, and -templated files. +template files. An initial `HEAD` file that references the HEAD of the master branch is also created. diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt index 209e36bacb..5a17801f6a 100644 --- a/Documentation/git-mailsplit.txt +++ b/Documentation/git-mailsplit.txt @@ -25,7 +25,7 @@ OPTIONS -b:: If any file doesn't begin with a From line, assume it is a - single mail message instead of signalling error. + single mail message instead of signaling error. -d<prec>:: Instead of the default 4 digits with leading zeros, diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 4ce799b520..bebf30ad3d 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -83,7 +83,7 @@ your local modifications interfere with the merge, again, it stops before touching anything. So in the above two "failed merge" case, you do not have to -worry about lossage of data --- you simply were not ready to do +worry about loss of data --- you simply were not ready to do a merge, so no merge happened at all. You may want to finish whatever you were in the middle of doing, and retry the same pull after you are done and ready. diff --git a/Documentation/git-p4import.txt b/Documentation/git-p4import.txt index 0858e5efbe..ee9e8fa909 100644 --- a/Documentation/git-p4import.txt +++ b/Documentation/git-p4import.txt @@ -128,7 +128,7 @@ Tags A git tag of the form p4/xx is created for every change imported from the Perforce repository where xx is the Perforce changeset number. Therefore after the import you can use git to access any commit by its -Perforce number, eg. git show p4/327. +Perforce number, e.g. git show p4/327. The tag associated with the HEAD commit is also how `git-p4import` determines if there are new changes to incrementally import from the @@ -143,7 +143,7 @@ may delete the tags. Notes ----- -You can interrupt the import (eg. ctrl-c) at any time and restart it +You can interrupt the import (e.g. ctrl-c) at any time and restart it without worry. Author information is automatically determined by querying the diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.txt index 8fb0659438..7d54b17e37 100644 --- a/Documentation/git-pack-redundant.txt +++ b/Documentation/git-pack-redundant.txt @@ -29,7 +29,7 @@ OPTIONS --all:: - Processes all packs. Any filenames on the commandline are ignored. + Processes all packs. Any filenames on the command line are ignored. --alt-odb:: Don't require objects present in packs from alternate object diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index d5b5ca167c..56afd64f42 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -67,7 +67,7 @@ Some short-cut notations are also supported. -f, \--force:: Usually, the command refuses to update a remote ref that is - not a descendent of the local ref used to overwrite it. + not a descendant of the local ref used to overwrite it. This flag disables the check. This can cause the remote repository to lose commits; use it with care. diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index 803c0d5cae..b03d66f61c 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -119,8 +119,8 @@ you can set the filemode to true with % git repo-config core.filemode true ------------ -The hypothetic proxy command entries actually have a postfix to discern -to what URL they apply. Here is how to change the entry for kernel.org +The hypothetical proxy command entries actually have a postfix to discern +what URL they apply to. Here is how to change the entry for kernel.org to "ssh". ------------ diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index ad6d14c55a..e220842981 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -15,6 +15,7 @@ SYNOPSIS [ \--sparse ] [ \--no-merges ] [ \--remove-empty ] + [ \--not ] [ \--all ] [ \--topo-order ] [ \--parents ] @@ -37,6 +38,14 @@ not in 'baz'". A special notation <commit1>..<commit2> can be used as a short-hand for {caret}<commit1> <commit2>. +Another special notation is <commit1>...<commit2> which is useful for +merges. The resulting set of commits is the symmetric difference +between the two operands. The following two commands are equivalent: + +------------ +$ git-rev-list A B --not $(git-merge-base --all A B) +$ git-rev-list A...B +------------ OPTIONS ------- @@ -55,7 +64,7 @@ OPTIONS --objects-edge:: Similar to `--objects`, but also print the IDs of - excluded commits refixed with a `-` character. This is + excluded commits prefixed with a `-` character. This is used by `git-pack-objects` to build 'thin' pack, which records objects in deltified form based on objects contained in these excluded commits to reduce network @@ -93,6 +102,11 @@ OPTIONS --remove-empty:: Stop when a given path disappears from the tree. +--not:: + Reverses the meaning of the '{caret}' prefix (or lack + thereof) for all following revision specifiers, up to + the next `--not`. + --all:: Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the command line as <commit>. diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 627cde8520..b761b4b965 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -156,11 +156,6 @@ syntax. and dereference the tag recursively until a non-tag object is found. -'git-rev-parse' also accepts a prefix '{caret}' to revision parameter, -which is passed to 'git-rev-list'. Two revision parameters -concatenated with '..' is a short-hand for writing a range -between them. I.e. 'r1..r2' is equivalent to saying '{caret}r1 r2' - Here is an illustration, by Jon Loeliger. Both node B and C are a commit parents of commit node A. Parent commits are ordered left-to-right. @@ -168,9 +163,9 @@ left-to-right. G H I J \ / \ / D E F - \ | / - \ | / - \|/ + \ | / \ + \ | / | + \|/ | B C \ / \ / @@ -188,6 +183,40 @@ left-to-right. J = F^2 = B^3^2 = A^^3^2 +SPECIFYING RANGES +----------------- + +History traversing commands such as `git-log` operate on a set +of commits, not just a single commit. To these commands, +specifying a single revision with the notation described in the +previous section means the set of commits reachable from that +commit, following the commit ancestry chain. + +To exclude commits reachable from a commit, a prefix `{caret}` +notation is used. E.g. "`{caret}r1 r2`" means commits reachable +from `r2` but exclude the ones reachable from `r1`. + +This set operation appears so often that there is a shorthand +for it. "`r1..r2`" is equivalent to "`{caret}r1 r2`". It is +the difference of two sets (subtract the set of commits +reachable from `r1` from the set of commits reachable from +`r2`). + +A similar notation "`r1\...r2`" is called symmetric difference +of `r1` and `r2` and is defined as +"`r1 r2 --not $(git-merge-base --all r1 r2)`". +It it the set of commits that are reachable from either one of +`r1` or `r2` but not from both. + +Here are a few examples: + + D A B D + D F A B C D F + ^A G B D + ^A F B C F + G...I C D F G I + ^B G I C D F G I + Author ------ Written by Linus Torvalds <torvalds@osdl.org> and diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index f115b45ef6..a2445a48fc 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -52,6 +52,11 @@ OPTIONS appear in topological order (i.e., descendant commits are shown before their parents). +--sparse:: + By default, the output omits merges that are reachable + from only one tip being shown. This option makes them + visible. + --more=<n>:: Usually the command stops output upon showing the commit that is the common ancestor of all the branches. This diff --git a/Documentation/git-tools.txt b/Documentation/git-tools.txt index d79523f56d..0914cbb0ba 100644 --- a/Documentation/git-tools.txt +++ b/Documentation/git-tools.txt @@ -42,7 +42,7 @@ History Viewers - *gitk* (shipped with git-core) - gitk is a simple TK GUI for browsing history of GIT repositories easily. + gitk is a simple Tk GUI for browsing history of GIT repositories easily. - *gitview* (contrib/) diff --git a/Documentation/git-upload-tar.txt b/Documentation/git-upload-tar.txt index a1019a0231..394af62015 100644 --- a/Documentation/git-upload-tar.txt +++ b/Documentation/git-upload-tar.txt @@ -17,7 +17,7 @@ to the other end over the git protocol. This command is usually not invoked directly by the end user. The UI for the protocol is on the 'git-tar-tree' side, and the -program pair is meant to be used to get a tar achive from a +program pair is meant to be used to get a tar archive from a remote repository. diff --git a/Documentation/git.txt b/Documentation/git.txt index 51f20c6e67..d00cc3ea52 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -478,7 +478,7 @@ Configuration Mechanism Starting from 0.99.9 (actually mid 0.99.8.GIT), `.git/config` file is used to hold per-repository configuration options. It is a -simple text file modelled after `.ini` format familiar to some +simple text file modeled after `.ini` format familiar to some people. Here is an example: ------------ diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt index 116ddb7fbf..14449ca8ba 100644 --- a/Documentation/glossary.txt +++ b/Documentation/glossary.txt @@ -86,7 +86,7 @@ directory:: ent:: Favorite synonym to "tree-ish" by some total geeks. See `http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth - explanation. + explanation. Avoid this term, not to confuse people. fast forward:: A fast-forward is a special type of merge where you have diff --git a/Documentation/howto/isolate-bugs-with-bisect.txt b/Documentation/howto/isolate-bugs-with-bisect.txt index edbcd4c661..926bbdc3cb 100644 --- a/Documentation/howto/isolate-bugs-with-bisect.txt +++ b/Documentation/howto/isolate-bugs-with-bisect.txt @@ -28,7 +28,7 @@ Then do and at this point "git bisect" will churn for a while, and tell you what the mid-point between those two commits are, and check that state out as -the head of the bew "bisect" branch. +the head of the new "bisect" branch. Compile and reboot. diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt index c2d4a91c7c..fcd64e9b9b 100644 --- a/Documentation/howto/rebase-from-internal-branch.txt +++ b/Documentation/howto/rebase-from-internal-branch.txt @@ -124,7 +124,7 @@ up your changes, along with other changes. The two commits #2' and #3' in the above picture record the same changes your e-mail submission for #2 and #3 contained, but -probably with the new sign-off line added by the upsteam +probably with the new sign-off line added by the upstream maintainer and definitely with different committer and ancestry information, they are different objects from #2 and #3 commits. diff --git a/Documentation/technical/pack-heuristics.txt b/Documentation/technical/pack-heuristics.txt index 9aadd5cee5..103eb5d989 100644 --- a/Documentation/technical/pack-heuristics.txt +++ b/Documentation/technical/pack-heuristics.txt @@ -73,7 +73,7 @@ The traditional insight: <pasky> yes -And Bable-like confusion flowed. +And Babel-like confusion flowed. <njs`> oh, hmm, and I'm not sure what this sliding window means either @@ -257,7 +257,7 @@ proclaim it a non-issue. Good style too! (type, basename, size)). Then we walk through this list, and calculate a delta of - each object against the last n (tunable paramater) objects, + each object against the last n (tunable parameter) objects, and pick the smallest of these deltas. Vastly simplified, but the essence is there! @@ -395,7 +395,7 @@ used as setup for a later optimization, which is a real word: do "object name->location in packfile" translation. <njs`> I'm assuming the real win for delta-ing large->small is - more homogenous statistics for gzip to run over? + more homogeneous statistics for gzip to run over? (You have to put the bytes in one place or another, but putting them in a larger blob wins on compression) @@ -448,7 +448,7 @@ design options, etc. Bugs happen, but they are "simple" bugs. And bugs that actually get some object store detail wrong are almost always - so obious that they never go anywhere. + so obvious that they never go anywhere. <njs`> Yeah. diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 74774134e3..d60b37147a 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -47,7 +47,7 @@ Then such a short-hand is specified in place of <repository> without <refspec> parameters on the command line, <refspec> specified on `Push:` lines or `Pull:` lines are used for `git-push` and `git-fetch`/`git-pull`, -respectively. Multiple `Push:` and and `Pull:` lines may +respectively. Multiple `Push:` and `Pull:` lines may be specified for additional branch mappings. The name of a file in `$GIT_DIR/branches` directory can be @@ -44,7 +44,7 @@ Issues of note: - "libcurl" and "curl" executable. git-http-fetch and git-fetch use them. If you do not use http - transfer, you are probabaly OK if you do not have + transfer, you are probably OK if you do not have them. - expat library; git-http-push uses it for remote lock @@ -69,7 +69,7 @@ Issues of note: git, and if you only use git to track other peoples work you'll never notice the lack of it. - - "wish", the TCL/Tk windowing shell is used in gitk to show the + - "wish", the Tcl/Tk windowing shell is used in gitk to show the history graphically - "ssh" is used to push and pull over the net @@ -64,7 +64,7 @@ all: # Define NO_ACCURATE_DIFF if your diff program at least sometimes misses # a missing newline at the end of the file. # -# Define NO_PYTHON if you want to loose all benefits of the recursive merge. +# Define NO_PYTHON if you want to lose all benefits of the recursive merge. # # Define COLLISION_CHECK below if you believe that SHA1's # 1461501637330902918203684832716283019655932542976 hashes do not give you @@ -473,7 +473,7 @@ ifdef NO_ACCURATE_DIFF ALL_CFLAGS += -DNO_ACCURATE_DIFF endif -# Shell quote (do not use $(call) to accomodate ancient setups); +# Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -518,6 +518,7 @@ common-cmds.h: Documentation/git-*.txt $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh rm -f $@ $@+ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ -e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \ @@ -556,9 +557,9 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ -e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \ - -e '/@@GITWEB_CGI@@/rgitweb/gitweb.cgi' \ + -e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \ -e '/@@GITWEB_CGI@@/d' \ - -e '/@@GITWEB_CSS@@/rgitweb/gitweb.css' \ + -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \ -e '/@@GITWEB_CSS@@/d' \ $@.sh > $@+ chmod +x $@+ diff --git a/builtin-add.c b/builtin-add.c index bfbbb1bf52..2d25698173 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -181,7 +181,7 @@ int cmd_add(int argc, const char **argv, char **envp) if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file)) + close(newfd) || commit_lock_file(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-apply.c b/builtin-apply.c index e9ead002d3..c3af48917c 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2323,7 +2323,7 @@ int cmd_apply(int argc, const char **argv, char **envp) if (write_index) { if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file)) + close(newfd) || commit_lock_file(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-log.c b/builtin-log.c index 864c6cd9ea..0aeeaa4e20 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -47,6 +47,7 @@ int cmd_whatchanged(int argc, const char **argv, char **envp) { struct rev_info rev; + git_config(git_diff_config); init_revisions(&rev); rev.diff = 1; rev.diffopt.recursive = 1; @@ -61,6 +62,7 @@ int cmd_show(int argc, const char **argv, char **envp) { struct rev_info rev; + git_config(git_diff_config); init_revisions(&rev); rev.diff = 1; rev.diffopt.recursive = 1; @@ -77,6 +79,7 @@ int cmd_log(int argc, const char **argv, char **envp) { struct rev_info rev; + git_config(git_diff_config); init_revisions(&rev); rev.always_show_header = 1; cmd_log_init(argc, argv, envp, &rev); @@ -102,7 +105,10 @@ static int git_format_config(const char *var, const char *value) strcat(extra_headers, value); return 0; } - return git_default_config(var, value); + if (!strcmp(var, "diff.color")) { + return 0; + } + return git_diff_config(var, value); } @@ -234,6 +240,7 @@ int cmd_format_patch(int argc, const char **argv, char **envp) struct diff_options patch_id_opts; char *add_signoff = NULL; + git_config(git_format_config); init_revisions(&rev); rev.commit_format = CMIT_FMT_EMAIL; rev.verbose_header = 1; @@ -243,7 +250,6 @@ int cmd_format_patch(int argc, const char **argv, char **envp) rev.diffopt.msg_sep = ""; rev.diffopt.recursive = 1; - git_config(git_format_config); rev.extra_headers = extra_headers; /* diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 9a2099d730..23a8d92a4b 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -1038,7 +1038,7 @@ int cmd_read_tree(int argc, const char **argv, char **envp) } if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file)) + close(newfd) || commit_lock_file(&lock_file)) die("unable to write new index file"); return 0; } diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 5f5ade45ae..b3e4386c1b 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -164,6 +164,51 @@ static int show_file(const char *arg) return 0; } +static int try_difference(const char *arg) +{ + char *dotdot; + unsigned char sha1[20]; + unsigned char end[20]; + const char *next; + const char *this; + int symmetric; + + if (!(dotdot = strstr(arg, ".."))) + return 0; + next = dotdot + 2; + this = arg; + symmetric = (*next == '.'); + + *dotdot = 0; + next += symmetric; + + if (!*next) + next = "HEAD"; + if (dotdot == arg) + this = "HEAD"; + if (!get_sha1(this, sha1) && !get_sha1(next, end)) { + show_rev(NORMAL, end, next); + show_rev(symmetric ? NORMAL : REVERSED, sha1, this); + if (symmetric) { + struct commit_list *exclude; + struct commit *a, *b; + a = lookup_commit_reference(sha1); + b = lookup_commit_reference(end); + exclude = get_merge_bases(a, b, 1); + while (exclude) { + struct commit_list *n = exclude->next; + show_rev(REVERSED, + exclude->item->object.sha1,NULL); + free(exclude); + exclude = n; + } + } + return 1; + } + *dotdot = '.'; + return 0; +} + int cmd_rev_parse(int argc, const char **argv, char **envp) { int i, as_is = 0, verify = 0; @@ -174,7 +219,6 @@ int cmd_rev_parse(int argc, const char **argv, char **envp) for (i = 1; i < argc; i++) { const char *arg = argv[i]; - char *dotdot; if (as_is) { if (show_file(arg) && as_is < 2) @@ -326,23 +370,8 @@ int cmd_rev_parse(int argc, const char **argv, char **envp) } /* Not a flag argument */ - dotdot = strstr(arg, ".."); - if (dotdot) { - unsigned char end[20]; - const char *next = dotdot + 2; - const char *this = arg; - *dotdot = 0; - if (!*next) - next = "HEAD"; - if (dotdot == arg) - this = "HEAD"; - if (!get_sha1(this, sha1) && !get_sha1(next, end)) { - show_rev(NORMAL, end, next); - show_rev(REVERSED, sha1, this); - continue; - } - *dotdot = '.'; - } + if (try_difference(arg)) + continue; if (!get_sha1(arg, sha1)) { show_rev(NORMAL, sha1, arg); continue; diff --git a/builtin-rm.c b/builtin-rm.c index 4d56a1f070..875d8252fa 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -147,7 +147,7 @@ int cmd_rm(int argc, const char **argv, char **envp) if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file)) + close(newfd) || commit_lock_file(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 09d8227862..260cb221b9 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -6,7 +6,7 @@ #include "builtin.h" static const char show_branch_usage[] = -"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]"; +"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]"; static int default_num = 0; static int default_alloc = 0; diff --git a/builtin-update-index.c b/builtin-update-index.c index ef50243452..1a4200d151 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -648,7 +648,7 @@ int cmd_update_index(int argc, const char **argv, char **envp) finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(lock_file)) + close(newfd) || commit_lock_file(lock_file)) die("Unable to write new index file"); } diff --git a/builtin-write-tree.c b/builtin-write-tree.c index 70e9b6fcc6..449a4d1b57 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -35,7 +35,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) missing_ok, 0) < 0) die("git-write-tree: error building trees"); if (0 <= newfd) { - if (!write_cache(newfd, active_cache, active_nr)) + if (!write_cache(newfd, active_cache, active_nr) + && !close(newfd)) commit_lock_file(lock_file); } /* Not being able to write is fine -- we are only interested @@ -382,6 +382,7 @@ extern int receive_keep_pack(int fd[2], const char *me, int quiet, int); /* pager.c */ extern void setup_pager(void); +extern int pager_in_use; /* base85 */ int decode_85(char *dst, char *line, int linelen); diff --git a/checkout-index.c b/checkout-index.c index ea40bc29be..2927955508 100644 --- a/checkout-index.c +++ b/checkout-index.c @@ -311,7 +311,7 @@ int main(int argc, char **argv) if (0 <= newfd && (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file))) + close(newfd) || commit_lock_file(&lock_file))) die("Unable to write new index file"); return 0; } @@ -397,12 +397,13 @@ void clear_commit_marks(struct commit *commit, unsigned int mark) { struct commit_list *parents; - parents = commit->parents; commit->object.flags &= ~mark; + parents = commit->parents; while (parents) { struct commit *parent = parents->item; - if (parent && parent->object.parsed && - (parent->object.flags & mark)) + + /* Have we already cleared this? */ + if (mark & parent->object.flags) clear_commit_marks(parent, mark); parents = parents->next; } @@ -846,3 +847,247 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo, } free(nodes); } + +/* merge-rebase stuff */ + +/* bits #0..7 in revision.h */ +#define PARENT1 (1u<< 8) +#define PARENT2 (1u<< 9) +#define STALE (1u<<10) + +static struct commit *interesting(struct commit_list *list) +{ + while (list) { + struct commit *commit = list->item; + list = list->next; + if (commit->object.flags & STALE) + continue; + return commit; + } + return NULL; +} + +/* + * A pathological example of how this thing works. + * + * Suppose we had this commit graph, where chronologically + * the timestamp on the commit are A <= B <= C <= D <= E <= F + * and we are trying to figure out the merge base for E and F + * commits. + * + * F + * / \ + * E A D + * \ / / + * B / + * \ / + * C + * + * First we push E and F to list to be processed. E gets bit 1 + * and F gets bit 2. The list becomes: + * + * list=F(2) E(1), result=empty + * + * Then we pop F, the newest commit, from the list. Its flag is 2. + * We scan its parents, mark them reachable from the side that F is + * reachable from, and push them to the list: + * + * list=E(1) D(2) A(2), result=empty + * + * Next pop E and do the same. + * + * list=D(2) B(1) A(2), result=empty + * + * Next pop D and do the same. + * + * list=C(2) B(1) A(2), result=empty + * + * Next pop C and do the same. + * + * list=B(1) A(2), result=empty + * + * Now it is B's turn. We mark its parent, C, reachable from B's side, + * and push it to the list: + * + * list=C(3) A(2), result=empty + * + * Now pop C and notice it has flags==3. It is placed on the result list, + * and the list now contains: + * + * list=A(2), result=C(3) + * + * We pop A and do the same. + * + * list=B(3), result=C(3) + * + * Next, we pop B and something very interesting happens. It has flags==3 + * so it is also placed on the result list, and its parents are marked + * stale, retroactively, and placed back on the list: + * + * list=C(7), result=C(7) B(3) + * + * Now, list does not have any interesting commit. So we find the newest + * commit from the result list that is not marked stale. Which is + * commit B. + * + * + * Another pathological example how this thing used to fail to mark an + * ancestor of a merge base as STALE before we introduced the + * postprocessing phase (mark_reachable_commits). + * + * 2 + * H + * 1 / \ + * G A \ + * |\ / \ + * | B \ + * | \ \ + * \ C F + * \ \ / + * \ D / + * \ | / + * \| / + * E + * + * list A B C D E F G H + * G1 H2 - - - - - - 1 2 + * H2 E1 B1 - 1 - - 1 - 1 2 + * F2 E1 B1 A2 2 1 - - 1 2 1 2 + * E3 B1 A2 2 1 - - 3 2 1 2 + * B1 A2 2 1 - - 3 2 1 2 + * C1 A2 2 1 1 - 3 2 1 2 + * D1 A2 2 1 1 1 3 2 1 2 + * A2 2 1 1 1 3 2 1 2 + * B3 2 3 1 1 3 2 1 2 + * C7 2 3 7 1 3 2 1 2 + * + * At this point, unfortunately, everybody in the list is + * stale, so we fail to complete the following two + * steps to fully marking stale commits. + * + * D7 2 3 7 7 3 2 1 2 + * E7 2 3 7 7 7 2 1 2 + * + * and we ended up showing E as an interesting merge base. + * The postprocessing phase re-injects C and continues traversal + * to contaminate D and E. + */ + +static void mark_reachable_commits(struct commit_list *result, + struct commit_list *list) +{ + struct commit_list *tmp; + + /* + * Postprocess to fully contaminate the well. + */ + for (tmp = result; tmp; tmp = tmp->next) { + struct commit *c = tmp->item; + /* Reinject stale ones to list, + * so we can scan their parents. + */ + if (c->object.flags & STALE) + commit_list_insert(c, &list); + } + while (list) { + struct commit *c = list->item; + struct commit_list *parents; + + tmp = list; + list = list->next; + free(tmp); + + /* Anything taken out of the list is stale, so + * mark all its parents stale. We do not + * parse new ones (we already parsed all the relevant + * ones). + */ + parents = c->parents; + while (parents) { + struct commit *p = parents->item; + parents = parents->next; + if (!(p->object.flags & STALE)) { + p->object.flags |= STALE; + commit_list_insert(p, &list); + } + } + } +} + +struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, + int cleanup) +{ + struct commit_list *list = NULL; + struct commit_list *result = NULL; + struct commit_list *tmp = NULL; + + if (rev1 == rev2) + return commit_list_insert(rev1, &result); + + parse_commit(rev1); + parse_commit(rev2); + + rev1->object.flags |= PARENT1; + rev2->object.flags |= PARENT2; + insert_by_date(rev1, &list); + insert_by_date(rev2, &list); + + while (interesting(list)) { + struct commit *commit = list->item; + struct commit_list *parents; + int flags = commit->object.flags + & (PARENT1 | PARENT2 | STALE); + + tmp = list; + list = list->next; + free(tmp); + if (flags == (PARENT1 | PARENT2)) { + insert_by_date(commit, &result); + + /* Mark parents of a found merge stale */ + flags |= STALE; + } + parents = commit->parents; + while (parents) { + struct commit *p = parents->item; + parents = parents->next; + if ((p->object.flags & flags) == flags) + continue; + parse_commit(p); + p->object.flags |= flags; + insert_by_date(p, &list); + } + } + + if (!result) + goto finish; + + if (result->next && list) + mark_reachable_commits(result, list); + + /* cull duplicates */ + for (tmp = result, list = NULL; tmp; ) { + struct commit *commit = tmp->item; + struct commit_list *next = tmp->next; + if (commit->object.flags & STALE) { + if (list != NULL) + list->next = next; + free(tmp); + } else { + if (list == NULL) + result = tmp; + list = tmp; + commit->object.flags |= STALE; + } + + tmp = next; + } + + finish: + if (cleanup) { + clear_commit_marks(rev1, PARENT1 | PARENT2 | STALE); + clear_commit_marks(rev2, PARENT1 | PARENT2 | STALE); + } + + return result; +} @@ -105,4 +105,6 @@ struct commit_graft *read_graft_line(char *buf, int len); int register_commit_graft(struct commit_graft *, int); int read_graft_file(const char *graft_file); +extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup); + #endif /* COMMIT_H */ @@ -110,8 +110,14 @@ int git_diff_config(const char *var, const char *value) if (!strcmp(var, "diff.color")) { if (!value) diff_use_color_default = 1; /* bool */ - else if (!strcasecmp(value, "auto")) - diff_use_color_default = isatty(1); + else if (!strcasecmp(value, "auto")) { + diff_use_color_default = 0; + if (isatty(1) || pager_in_use) { + char *term = getenv("TERM"); + if (term && strcmp(term, "dumb")) + diff_use_color_default = 1; + } + } else if (!strcasecmp(value, "never")) diff_use_color_default = 0; else if (!strcasecmp(value, "always")) @@ -329,7 +335,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) } if (len > 0 && line[len-1] == '\n') len--; - printf("%s%.*s%s\n", set, (int) len, line, reset); + fputs (set, stdout); + fwrite (line, len, 1, stdout); + puts (reset); } static char *pprint_rename(const char *a, const char *b) @@ -721,7 +729,7 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) { + if (!o->text && (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))) { /* Quite common confusing case */ if (mf1.size == mf2.size && !memcmp(mf1.ptr, mf2.ptr, mf1.size)) @@ -1559,6 +1567,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->output_format |= DIFF_FORMAT_PATCH; options->full_index = options->binary = 1; } + else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) { + options->text = 1; + } else if (!strcmp(arg, "--name-only")) options->output_format |= DIFF_FORMAT_NAME; else if (!strcmp(arg, "--name-status")) @@ -42,6 +42,7 @@ struct diff_options { unsigned recursive:1, tree_in_recursive:1, binary:1, + text:1, full_index:1, silent_on_remove:1, find_copies_harder:1, @@ -161,7 +162,8 @@ extern void diffcore_std_no_resolve(struct diff_options *); " -O<file> reorder diffs according to the <file>.\n" \ " -S<string> find filepair whose only one side contains the string.\n" \ " --pickaxe-all\n" \ -" show all files diff when -S is used and hit is found.\n" +" show all files diff when -S is used and hit is found.\n" \ +" -a --text treat all files as text.\n" extern int diff_queue_is_empty(void); extern void diff_flush(struct diff_options*); diff --git a/git-bisect.sh b/git-bisect.sh index 03df1433ef..06a8d26945 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -13,7 +13,7 @@ git bisect log show bisect log.' . git-sh-setup sq() { - perl -e ' + @@PERL@@ -e ' for (@ARGV) { s/'\''/'\'\\\\\'\''/g; print " '\''$_'\''"; diff --git a/git-clone.sh b/git-clone.sh index 6a14b25911..0368803883 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -324,7 +324,7 @@ test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" if test -f "$GIT_DIR/CLONE_HEAD" then # Read git-fetch-pack -k output and store the remote branches. - perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" + @@PERL@@ -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" fi cd "$D" || exit diff --git a/git-commit.sh b/git-commit.sh index 22c4ce86c3..08d786db2f 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -147,7 +147,7 @@ run_status () { git-ls-files -z --others $option \ --exclude-per-directory=.gitignore fi | - perl -e '$/ = "\0"; + @@PERL@@ -e '$/ = "\0"; my $shown = 0; while (<>) { chomp; diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index d1051d074b..5dcb2f9a8e 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -63,15 +63,15 @@ foreach my $p (@commit) { } if ($parent) { + my $found; # double check that it's a valid parent foreach my $p (@parents) { - my $found; if ($p eq $parent) { $found = 1; last; }; # found it - die "Did not find $parent in the parents for this commit!"; } + die "Did not find $parent in the parents for this commit!" if !$found; } else { # we don't have a parent from the cmdline... if (@parents == 1) { # it's safe to get it from the commit $parent = $parents[0]; diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 5ccca4f99f..c30ef70427 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -779,7 +779,7 @@ sub req_update #$log->debug("update state : " . Dumper($state)); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); @@ -1031,7 +1031,7 @@ sub req_ci my @committedfiles = (); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { my $committedfile = $filename; @@ -1145,7 +1145,7 @@ sub req_ci $updater->update(); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @committedfiles ) { $filename = filecleanup($filename); @@ -1190,7 +1190,7 @@ sub req_status # if no files were specified, we need to work out what files we should be providing status on ... argsfromdir($updater); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); @@ -1291,7 +1291,7 @@ sub req_diff # if no files were specified, we need to work out what files we should be providing status on ... argsfromdir($updater); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); @@ -1433,7 +1433,7 @@ sub req_log # if no files were specified, we need to work out what files we should be providing status on ... argsfromdir($updater); - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); @@ -1519,7 +1519,7 @@ sub req_annotate chdir $tmpdir; - # foreach file specified on the commandline ... + # foreach file specified on the command line ... foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); diff --git a/git-fetch.sh b/git-fetch.sh index 48818f8224..f80299daaa 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -278,7 +278,7 @@ fetch_main () { head="ref: $remote_name" while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null do - remote_name_quoted=$(perl -e ' + remote_name_quoted=$(@@PERL@@ -e ' my $u = $ARGV[0]; $u =~ s/^ref:\s*//; $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; diff --git a/git-rebase.sh b/git-rebase.sh index 3945e06714..1b9e986926 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -311,7 +311,7 @@ echo "$prev_head" > "$dotest/prev_head" msgnum=0 for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \ - | perl -e 'print reverse <>'` + | @@PERL@@ -e 'print reverse <>'` do msgnum=$(($msgnum + 1)) echo "$cmt" > "$dotest/cmt.$msgnum" diff --git a/git-send-email.perl b/git-send-email.perl index b04b8f40e9..c9c1975b7f 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -34,8 +34,43 @@ sub readline { package main; # most mail servers generate the Date: header, but not all... -$ENV{LC_ALL} = 'C'; -use POSIX qw/strftime/; +sub format_2822_time { + my ($time) = @_; + my @localtm = localtime($time); + my @gmttm = gmtime($time); + my $localmin = $localtm[1] + $localtm[2] * 60; + my $gmtmin = $gmttm[1] + $gmttm[2] * 60; + if ($localtm[0] != $gmttm[0]) { + die "local zone differs from GMT by a non-minute interval\n"; + } + if ((($gmttm[6] + 1) % 7) == $localtm[6]) { + $localmin += 1440; + } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) { + $localmin -= 1440; + } elsif ($gmttm[6] != $localtm[6]) { + die "local time offset greater than or equal to 24 hours\n"; + } + my $offset = $localmin - $gmtmin; + my $offhour = $offset / 60; + my $offmin = abs($offset % 60); + if (abs($offhour) >= 24) { + die ("local time offset greater than or equal to 24 hours\n"); + } + + return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d", + qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]], + $localtm[3], + qw(Jan Feb Mar Apr May Jun + Jul Aug Sep Oct Nov Dec)[$localtm[4]], + $localtm[5]+1900, + $localtm[2], + $localtm[1], + $localtm[0], + ($offset >= 0) ? '+' : '-', + abs($offhour), + $offmin, + ); +} my $have_email_valid = eval { require Email::Valid; 1 }; my $smtp; @@ -387,7 +422,7 @@ sub send_message my @recipients = unique_email_list(@to); my $to = join (",\n\t", @recipients); @recipients = unique_email_list(@recipients,@cc,@bcclist); - my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime($time++)); + my $date = format_2822_time($time++); my $gitversion = '@@GIT_VERSION@@'; if ($gitversion =~ m/..GIT_VERSION../) { $gitversion = `git --version`; @@ -251,6 +251,11 @@ int main(int argc, const char **argv, char **envp) cmd = *++argv; argc--; + if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { + setup_pager(); + continue; + } + if (strncmp(cmd, "--", 2)) break; diff --git a/merge-base.c b/merge-base.c index 4856ca01c3..59f723f404 100644 --- a/merge-base.c +++ b/merge-base.c @@ -2,232 +2,22 @@ #include "cache.h" #include "commit.h" -#define PARENT1 1 -#define PARENT2 2 -#define UNINTERESTING 4 - -static struct commit *interesting(struct commit_list *list) -{ - while (list) { - struct commit *commit = list->item; - list = list->next; - if (commit->object.flags & UNINTERESTING) - continue; - return commit; - } - return NULL; -} - -/* - * A pathological example of how this thing works. - * - * Suppose we had this commit graph, where chronologically - * the timestamp on the commit are A <= B <= C <= D <= E <= F - * and we are trying to figure out the merge base for E and F - * commits. - * - * F - * / \ - * E A D - * \ / / - * B / - * \ / - * C - * - * First we push E and F to list to be processed. E gets bit 1 - * and F gets bit 2. The list becomes: - * - * list=F(2) E(1), result=empty - * - * Then we pop F, the newest commit, from the list. Its flag is 2. - * We scan its parents, mark them reachable from the side that F is - * reachable from, and push them to the list: - * - * list=E(1) D(2) A(2), result=empty - * - * Next pop E and do the same. - * - * list=D(2) B(1) A(2), result=empty - * - * Next pop D and do the same. - * - * list=C(2) B(1) A(2), result=empty - * - * Next pop C and do the same. - * - * list=B(1) A(2), result=empty - * - * Now it is B's turn. We mark its parent, C, reachable from B's side, - * and push it to the list: - * - * list=C(3) A(2), result=empty - * - * Now pop C and notice it has flags==3. It is placed on the result list, - * and the list now contains: - * - * list=A(2), result=C(3) - * - * We pop A and do the same. - * - * list=B(3), result=C(3) - * - * Next, we pop B and something very interesting happens. It has flags==3 - * so it is also placed on the result list, and its parents are marked - * uninteresting, retroactively, and placed back on the list: - * - * list=C(7), result=C(7) B(3) - * - * Now, list does not have any interesting commit. So we find the newest - * commit from the result list that is not marked uninteresting. Which is - * commit B. - * - * - * Another pathological example how this thing used to fail to mark an - * ancestor of a merge base as UNINTERESTING before we introduced the - * postprocessing phase (mark_reachable_commits). - * - * 2 - * H - * 1 / \ - * G A \ - * |\ / \ - * | B \ - * | \ \ - * \ C F - * \ \ / - * \ D / - * \ | / - * \| / - * E - * - * list A B C D E F G H - * G1 H2 - - - - - - 1 2 - * H2 E1 B1 - 1 - - 1 - 1 2 - * F2 E1 B1 A2 2 1 - - 1 2 1 2 - * E3 B1 A2 2 1 - - 3 2 1 2 - * B1 A2 2 1 - - 3 2 1 2 - * C1 A2 2 1 1 - 3 2 1 2 - * D1 A2 2 1 1 1 3 2 1 2 - * A2 2 1 1 1 3 2 1 2 - * B3 2 3 1 1 3 2 1 2 - * C7 2 3 7 1 3 2 1 2 - * - * At this point, unfortunately, everybody in the list is - * uninteresting, so we fail to complete the following two - * steps to fully marking uninteresting commits. - * - * D7 2 3 7 7 3 2 1 2 - * E7 2 3 7 7 7 2 1 2 - * - * and we ended up showing E as an interesting merge base. - * The postprocessing phase re-injects C and continues traversal - * to contaminate D and E. - */ - static int show_all = 0; -static void mark_reachable_commits(struct commit_list *result, - struct commit_list *list) -{ - struct commit_list *tmp; - - /* - * Postprocess to fully contaminate the well. - */ - for (tmp = result; tmp; tmp = tmp->next) { - struct commit *c = tmp->item; - /* Reinject uninteresting ones to list, - * so we can scan their parents. - */ - if (c->object.flags & UNINTERESTING) - commit_list_insert(c, &list); - } - while (list) { - struct commit *c = list->item; - struct commit_list *parents; - - tmp = list; - list = list->next; - free(tmp); - - /* Anything taken out of the list is uninteresting, so - * mark all its parents uninteresting. We do not - * parse new ones (we already parsed all the relevant - * ones). - */ - parents = c->parents; - while (parents) { - struct commit *p = parents->item; - parents = parents->next; - if (!(p->object.flags & UNINTERESTING)) { - p->object.flags |= UNINTERESTING; - commit_list_insert(p, &list); - } - } - } -} - static int merge_base(struct commit *rev1, struct commit *rev2) { - struct commit_list *list = NULL; - struct commit_list *result = NULL; - struct commit_list *tmp = NULL; - - if (rev1 == rev2) { - printf("%s\n", sha1_to_hex(rev1->object.sha1)); - return 0; - } - - parse_commit(rev1); - parse_commit(rev2); - - rev1->object.flags |= 1; - rev2->object.flags |= 2; - insert_by_date(rev1, &list); - insert_by_date(rev2, &list); - - while (interesting(list)) { - struct commit *commit = list->item; - struct commit_list *parents; - int flags = commit->object.flags & 7; - - tmp = list; - list = list->next; - free(tmp); - if (flags == 3) { - insert_by_date(commit, &result); - - /* Mark parents of a found merge uninteresting */ - flags |= UNINTERESTING; - } - parents = commit->parents; - while (parents) { - struct commit *p = parents->item; - parents = parents->next; - if ((p->object.flags & flags) == flags) - continue; - parse_commit(p); - p->object.flags |= flags; - insert_by_date(p, &list); - } - } + struct commit_list *result = get_merge_bases(rev1, rev2, 0); if (!result) return 1; - if (result->next && list) - mark_reachable_commits(result, list); - while (result) { - struct commit *commit = result->item; - result = result->next; - if (commit->object.flags & UNINTERESTING) - continue; - printf("%s\n", sha1_to_hex(commit->object.sha1)); + printf("%s\n", sha1_to_hex(result->item->object.sha1)); if (!show_all) return 0; - commit->object.flags |= UNINTERESTING; + result = result->next; } + return 0; } @@ -5,6 +5,8 @@ * something different on Windows, for example. */ +int pager_in_use; + static void run_pager(const char *pager) { execlp(pager, pager, NULL); @@ -24,6 +26,8 @@ void setup_pager(void) else if (!*pager || !strcmp(pager, "cat")) return; + pager_in_use = 1; /* means we are emitting to terminal */ + if (pipe(fd) < 0) return; pid = fork(); @@ -362,7 +362,7 @@ static int log_ref_write(struct ref_lock *lock, int logfd, written, oflags = O_APPEND | O_WRONLY; unsigned maxlen, len; char *logrec; - const char *comitter; + const char *committer; if (log_all_ref_updates) { if (safe_create_leading_directories(lock->log_file) < 0) @@ -380,23 +380,23 @@ static int log_ref_write(struct ref_lock *lock, } setup_ident(); - comitter = git_committer_info(1); + committer = git_committer_info(1); if (msg) { - maxlen = strlen(comitter) + strlen(msg) + 2*40 + 5; + maxlen = strlen(committer) + strlen(msg) + 2*40 + 5; logrec = xmalloc(maxlen); len = snprintf(logrec, maxlen, "%s %s %s\t%s\n", sha1_to_hex(lock->old_sha1), sha1_to_hex(sha1), - comitter, + committer, msg); } else { - maxlen = strlen(comitter) + 2*40 + 4; + maxlen = strlen(committer) + 2*40 + 4; logrec = xmalloc(maxlen); len = snprintf(logrec, maxlen, "%s %s %s\n", sha1_to_hex(lock->old_sha1), sha1_to_hex(sha1), - comitter); + committer); } written = len <= maxlen ? write(logfd, logrec, len) : -1; free(logrec); diff --git a/revision.c b/revision.c index ab89c22417..a7750e626b 100644 --- a/revision.c +++ b/revision.c @@ -537,6 +537,18 @@ void init_revisions(struct rev_info *revs) diff_setup(&revs->diffopt); } +static void add_pending_commit_list(struct rev_info *revs, + struct commit_list *commit_list, + unsigned int flags) +{ + while (commit_list) { + struct object *object = &commit_list->item->object; + object->flags |= flags; + add_pending_object(revs, object, sha1_to_hex(object->sha1)); + commit_list = commit_list->next; + } +} + /* * Parse revision information, filling in the "rev_info" structure, * and removing the used arguments from the argument list. @@ -772,27 +784,46 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch unsigned char from_sha1[20]; const char *next = dotdot + 2; const char *this = arg; + int symmetric = *next == '.'; + unsigned int flags_exclude = flags ^ UNINTERESTING; + *dotdot = 0; + next += symmetric; + if (!*next) next = "HEAD"; if (dotdot == arg) this = "HEAD"; if (!get_sha1(this, from_sha1) && !get_sha1(next, sha1)) { - struct object *exclude; - struct object *include; - - exclude = get_reference(revs, this, from_sha1, flags ^ UNINTERESTING); - include = get_reference(revs, next, sha1, flags); - if (!exclude || !include) - die("Invalid revision range %s..%s", arg, next); + struct commit *a, *b; + struct commit_list *exclude; + + a = lookup_commit_reference(from_sha1); + b = lookup_commit_reference(sha1); + if (!a || !b) { + die(symmetric ? + "Invalid symmetric difference expression %s...%s" : + "Invalid revision range %s..%s", + arg, next); + } if (!seen_dashdash) { *dotdot = '.'; verify_non_filename(revs->prefix, arg); } - add_pending_object(revs, exclude, this); - add_pending_object(revs, include, next); + + if (symmetric) { + exclude = get_merge_bases(a, b, 1); + add_pending_commit_list(revs, exclude, + flags_exclude); + free_commit_list(exclude); + a->object.flags |= flags; + } else + a->object.flags |= flags_exclude; + b->object.flags |= flags; + add_pending_object(revs, &a->object, this); + add_pending_object(revs, &b->object, next); continue; } *dotdot = '.'; diff --git a/server-info.c b/server-info.c index 0eb5132cc1..fdfe05a2da 100644 --- a/server-info.c +++ b/server-info.c @@ -94,7 +94,7 @@ static int read_pack_info_file(const char *infofile) fp = fopen(infofile, "r"); if (!fp) - return 1; /* nonexisting is not an error. */ + return 1; /* nonexistent is not an error. */ while (fgets(line, sizeof(line), fp)) { int len = strlen(line); |