diff options
171 files changed, 2281 insertions, 680 deletions
diff --git a/Documentation/RelNotes-1.5.2.txt b/Documentation/RelNotes-1.5.2.txt index 6195715dc7..e8328d090a 100644 --- a/Documentation/RelNotes-1.5.2.txt +++ b/Documentation/RelNotes-1.5.2.txt @@ -36,7 +36,7 @@ Updates since v1.5.1 expansion). These conversions apply when checking files in or out, and exporting via git-archive. -* The packfile format now optionally suports 64-bit index. +* The packfile format now optionally supports 64-bit index. This release supports the "version 2" format of the .idx file. This is automatically enabled when a huge packfile diff --git a/Documentation/RelNotes-1.5.3.txt b/Documentation/RelNotes-1.5.3.txt index d03894b926..0668d3c0ca 100644 --- a/Documentation/RelNotes-1.5.3.txt +++ b/Documentation/RelNotes-1.5.3.txt @@ -86,7 +86,7 @@ Updates since v1.5.2 - "git rev-list" learned --regexp-ignore-case and --extended-regexp options to tweak its matching logic used - for --grep fitering. + for --grep filtering. - "git describe --contains" is a handier way to call more obscure command "git name-rev --tags". @@ -243,7 +243,7 @@ Updates since v1.5.2 - We used to have core.legacyheaders configuration, when set to false, allowed git to write loose objects in a format - that mimicks the format used by objects stored in packs. It + that mimics the format used by objects stored in packs. It turns out that this was not so useful. Although we will continue to read objects written in that format, we do not honor that configuration anymore and create loose objects in @@ -302,7 +302,7 @@ Updates since v1.5.2 small enough delta results it creates while looking for the best delta candidates. - - "git pack-objects" learned a new heuristcs to prefer delta + - "git pack-objects" learned a new heuristic to prefer delta that is shallower in depth over the smallest delta possible. This improves both overall packfile access performance and packfile density. diff --git a/Documentation/RelNotes-1.5.4.4.txt b/Documentation/RelNotes-1.5.4.4.txt index 89fa6d03bc..323c1a88c7 100644 --- a/Documentation/RelNotes-1.5.4.4.txt +++ b/Documentation/RelNotes-1.5.4.4.txt @@ -55,7 +55,7 @@ Fixes since v1.5.4.3 * "git log --merge" did not work well with --left-right option. - * "git svn" promprted for client cert password every time it accessed the + * "git svn" prompted for client cert password every time it accessed the server. * The reset command in "git fast-import" data stream was documented to diff --git a/Documentation/RelNotes-1.5.4.5.txt b/Documentation/RelNotes-1.5.4.5.txt index 0282341398..bbd130e36d 100644 --- a/Documentation/RelNotes-1.5.4.5.txt +++ b/Documentation/RelNotes-1.5.4.5.txt @@ -9,7 +9,7 @@ Fixes since v1.5.4.4 1.5.4). * Bogus refspec configuration such as "remote.there.fetch = =" were not - detected as errors (regressionin 1.5.4). + detected as errors (regression in 1.5.4). * You couldn't specify a custom editor whose path contains a whitespace via GIT_EDITOR (and core.editor). diff --git a/Documentation/RelNotes-1.5.4.6.txt b/Documentation/RelNotes-1.5.4.6.txt new file mode 100644 index 0000000000..3e3c3e55a3 --- /dev/null +++ b/Documentation/RelNotes-1.5.4.6.txt @@ -0,0 +1,43 @@ +GIT v1.5.4.6 Release Notes +========================== + +I personally do not think there is any reason anybody should want to +run v1.5.4.X series these days, because 'master' version is always +more stable than any tagged released version of git. + +This is primarily to futureproof "git-shell" to accept requests +without a dash between "git" and subcommand name (e.g. "git +upload-pack") which the newer client will start to make sometime in +the future. + +Fixes since v1.5.4.5 +-------------------- + + * Command line option "-n" to "git-repack" was not correctly parsed. + + * Error messages from "git-apply" when the patchfile cannot be opened + have been improved. + + * Error messages from "git-bisect" when given nonsense revisions have + been improved. + + * reflog syntax that uses time e.g. "HEAD@{10 seconds ago}:path" did not + stop parsing at the closing "}". + + * "git rev-parse --symbolic-full-name ^master^2" printed solitary "^", + but it should print nothing. + + * "git apply" did not enforce "match at the beginning" correctly. + + * a path specification "a/b" in .gitattributes file should not match + "sub/a/b", but it did. + + * "git log --date-order --topo-order" did not override the earlier + date-order with topo-order as expected. + + * "git fast-export" did not export octopus merges correctly. + + * "git archive --prefix=$path/" mishandled gitattributes. + +As usual, it also comes with many documentation fixes and clarifications. + diff --git a/Documentation/RelNotes-1.5.5.5.txt b/Documentation/RelNotes-1.5.5.5.txt new file mode 100644 index 0000000000..30fa3615c7 --- /dev/null +++ b/Documentation/RelNotes-1.5.5.5.txt @@ -0,0 +1,11 @@ +GIT v1.5.5.5 Release Notes +========================== + +I personally do not think there is any reason anybody should want to +run v1.5.5.X series these days, because 'master' version is always +more stable than any tagged released version of git. + +This is primarily to futureproof "git-shell" to accept requests +without a dash between "git" and subcommand name (e.g. "git +upload-pack") which the newer client will start to make sometime in +the future. diff --git a/Documentation/RelNotes-1.5.6.1.txt b/Documentation/RelNotes-1.5.6.1.txt new file mode 100644 index 0000000000..4864b16445 --- /dev/null +++ b/Documentation/RelNotes-1.5.6.1.txt @@ -0,0 +1,28 @@ +GIT v1.5.6.1 Release Notes +========================== + +Fixes since v1.5.6 +------------------ + +* Last minute change broke loose object creation on AIX. + +* (performance fix) We used to make $GIT_DIR absolute path early in the + programs but keeping it relative to the current directory internally + gives 1-3 per-cent performance boost. + +* bash completion knows the new --graph option to git-log family. + + +* git-diff -c/--cc showed unnecessary "deletion" lines at the context + boundary. + +* git-for-each-ref ignored %(object) and %(type) requests for tag + objects. + +* git-merge usage had a typo. + +* Rebuilding of git-svn metainfo database did not take rewriteRoot + option into account. + +* Running "git-rebase --continue/--skip/--abort" before starting a + rebase gave nonsense error messages. diff --git a/Documentation/RelNotes-1.5.6.2.txt b/Documentation/RelNotes-1.5.6.2.txt new file mode 100644 index 0000000000..5902a85a78 --- /dev/null +++ b/Documentation/RelNotes-1.5.6.2.txt @@ -0,0 +1,40 @@ +GIT v1.5.6.2 Release Notes +========================== + +Futureproof +----------- + + * "git-shell" accepts requests without a dash between "git" and + subcommand name (e.g. "git upload-pack") which the newer client will + start to make sometime in the future. + +Fixes since v1.5.6.1 +-------------------- + +* "git clone" from a remote that is named with url.insteadOf setting in + $HOME/.gitconfig did not work well. + +* "git describe --long --tags" segfaulted when the described revision was + tagged with a lightweight tag. + +* "git diff --check" did not report the result via its exit status + reliably. + +* When remote side used to have branch 'foo' and git-fetch finds that now + it has branch 'foo/bar', it refuses to lose the existing remote tracking + branch and its reflog. The error message has been improved to suggest + pruning the remote if the user wants to proceed and get the latest set + of branches from the remote, including such 'foo/bar'. + +* "git reset file" should mean the same thing as "git reset HEAD file", + but we required disambiguating -- even when "file" is not ambiguous. + +* "git show" segfaulted when an annotated tag that points at another + annotated tag was given to it. + +* Optimization for a large import via "git-svn" introduced in v1.5.6 had a + serious memory and temporary file leak, which made it unusable for + moderately large import. + +* "git-svn" mangled remote nickname used in the configuration file + unnecessarily. diff --git a/Documentation/RelNotes-1.5.6.3.txt b/Documentation/RelNotes-1.5.6.3.txt new file mode 100644 index 0000000000..942611299d --- /dev/null +++ b/Documentation/RelNotes-1.5.6.3.txt @@ -0,0 +1,52 @@ +GIT v1.5.6.3 Release Notes +========================== + +Fixes since v1.5.6.2 +-------------------- + +* Setting core.sharerepository to traditional "true" value was supposed to make + the repository group writable but should not affect permission for others. + However, since 1.5.6, it was broken to drop permission for others when umask is + 022, making the repository unreadable by others. + +* Setting GIT_TRACE will report spawning of external process via run_command(). + +* Using an object with very deep delta chain pinned memory needed for extracting + intermediate base objects unnecessarily long, leading to excess memory usage. + +* Bash completion script did not notice '--' marker on the command + line and tried the relatively slow "ref completion" even when + completing arguments after one. + +* Registering a non-empty blob racily and then truncating the working + tree file for it confused "racy-git avoidance" logic into thinking + that the path is now unchanged. + +* The section that describes attributes related to git-archive were placed + in a wrong place in the gitattributes(5) manual page. + +* "git am" was not helpful to the users when it detected that the committer + information is not set up properly yet. + +* "git clone" had a leftover debugging fprintf(). + +* "git clone -q" was not quiet enough as it used to and gave object count + and progress reports. + +* "git clone" marked downloaded packfile with .keep; this could be a + good thing if the remote side is well packed but otherwise not, + especially for a project that is not really big. + +* "git daemon" used to call syslog() from a signal handler, which + could raise signals of its own but generally is not reentrant. This + was fixed by restructuring the code to report syslog() after the handler + returns. + +* When "git push" tries to remove a remote ref, and corresponding + tracking ref is missing, we used to report error (i.e. failure to + remove something that does not exist). + +* "git mailinfo" (hence "git am") did not handle commit log messages in a + MIME multipart mail correctly. + +Contains other various documentation fixes. diff --git a/Documentation/RelNotes-1.5.6.4.txt b/Documentation/RelNotes-1.5.6.4.txt new file mode 100644 index 0000000000..d8968f1ecb --- /dev/null +++ b/Documentation/RelNotes-1.5.6.4.txt @@ -0,0 +1,47 @@ +GIT v1.5.6.4 Release Notes +========================== + +Fixes since v1.5.6.3 +-------------------- + +* Various commands could overflow its internal buffer on a platform + with small PATH_MAX value in a repository that has contents with + long pathnames. + +* There wasn't a way to make --pretty=format:%<> specifiers to honor + .mailmap name rewriting for authors and committers. Now you can with + %aN and %cN. + +* Bash completion wasted too many cycles; this has been optimized to be + usable again. + +* Bash completion lost ref part when completing something like "git show + pu:Makefile". + +* "git-cvsserver" did not clean up its temporary working area after annotate + request. + +* "git-daemon" called syslog() from its signal handler, which was a + no-no. + +* "git-fetch" into an empty repository used to remind that the fetch will + be huge by saying "no common commits", but this was an unnecessary + noise; it is already known by the user anyway. + +* "git-http-fetch" would have segfaulted when pack idx file retrieved + from the other side was corrupt. + +* "git-index-pack" used too much memory when dealing with a deep delta chain. + +* "git-mailinfo" (hence "git-am") did not correctly handle in-body [PATCH] + line to override the commit title taken from the mail Subject header. + +* "git-rebase -i -p" lost parents that are not involved in the history + being rewritten. + +* "git-rm" lost track of where the index file was when GIT_DIR was + specified as a relative path. + +* "git-rev-list --quiet" was not quiet as advertised. + +Contains other various documentation fixes. diff --git a/Documentation/RelNotes-1.5.6.5.txt b/Documentation/RelNotes-1.5.6.5.txt new file mode 100644 index 0000000000..47ca172462 --- /dev/null +++ b/Documentation/RelNotes-1.5.6.5.txt @@ -0,0 +1,29 @@ +GIT v1.5.6.5 Release Notes +========================== + +Fixes since v1.5.6.4 +-------------------- + +* "git cvsimport" used to spit out "UNKNOWN LINE..." diagnostics to stdout. + +* "git commit -F filename" and "git tag -F filename" run from subdirectories + did not read the right file. + +* "git init --template=" with blank "template" parameter linked files + under root directories to .git, which was a total nonsense. Instead, it + means "I do not want to use anything from the template directory". + +* "git diff-tree" and other diff plumbing ignored diff.renamelimit configuration + variable when the user explicitly asked for rename detection. + +* "git name-rev --name-only" did not work when "--stdin" option was in effect. + +* "git show-branch" mishandled its 8th branch. + +* Addition of "git update-index --ignore-submodules" that happened during + 1.5.6 cycle broke "git update-index --ignore-missing". + +* "git send-email" did not parse charset from an existing Content-type: + header properly. + +Contains other various documentation fixes. diff --git a/Documentation/RelNotes-1.5.6.txt b/Documentation/RelNotes-1.5.6.txt index b22bfa89a8..e143d8d61b 100644 --- a/Documentation/RelNotes-1.5.6.txt +++ b/Documentation/RelNotes-1.5.6.txt @@ -18,6 +18,8 @@ Updates since v1.5.5 * "git init" now autodetects the case sensitivity of the filesystem and sets core.ignorecase accordingly. +* cpio is no longer used; neither "curl" binary (libcurl is still used). + (documentation) * Many freestanding documentation pages have been converted and made @@ -110,9 +112,4 @@ Fixes since v1.5.5 All of the fixes in v1.5.5 maintenance series are included in this release, unless otherwise noted. - --- -exec >/var/tmp/1 -O=v1.5.6-rc3 -echo O=`git describe refs/heads/master` -git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint +And there are too numerous small fixes to otherwise note here ;-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 5331b450ea..d4ca8b2712 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -92,7 +92,7 @@ Example # Our diff algorithm [diff] - external = "/usr/local/bin/gnu-diff -u" + external = /usr/local/bin/diff-wrapper renames = true [branch "devel"] @@ -554,9 +554,11 @@ diff.autorefreshindex:: diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the - given command. Note: if you want to use an external diff - program only on a subset of your files, you might want to - use linkgit:gitattributes[5] instead. + given command. Can be overridden with the `GIT_EXTERNAL_DIFF' + environment variable. The command is called with parameters + as described under "git Diffs" in linkgit:git[1]. Note: if + you want to use an external diff program only on a subset of + your files, you might want to use linkgit:gitattributes[5] instead. diff.renameLimit:: The number of files to consider when performing the copy/rename diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt index 029c5f2b82..517e1eba3c 100644 --- a/Documentation/diff-generate-patch.txt +++ b/Documentation/diff-generate-patch.txt @@ -96,7 +96,7 @@ index fabadb8,cc95eb0..4866510 + or like this (when '--cc' option is used): - diff --c file + diff --cc file 2. It is followed by one or more extended header lines (this example shows a merge with two parents): diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index b8e3fa6759..815864c37f 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -187,8 +187,9 @@ update:: "Update>>". When the prompt ends with double '>>', you can make more than one selection, concatenated with whitespace or comma. Also you can say ranges. E.g. "2-5 7,9" to choose - 2,3,4,5,7,9 from the list. You can say '*' to choose - everything. + 2,3,4,5,7,9 from the list. If the second number in a range is + omitted, all remaining patches are taken. E.g. "7-" to choose + 7,8,9 from the list. You can say '*' to choose everything. + What you chose are then highlighted with '*', like this: diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 46544a0769..5622971f6a 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -153,7 +153,7 @@ linkgit:git-apply[1]. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index 8f4fb46685..0e0196e5b0 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -190,7 +190,7 @@ linkgit:git-annotate[1] AUTHOR ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> GIT --- diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 0fd58083eb..39cd5d961f 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -202,7 +202,7 @@ but different purposes: Author ------ -Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <junkio@cox.net> +Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt index ef16b93982..f8e1bd5027 100644 --- a/Documentation/git-check-attr.txt +++ b/Documentation/git-check-attr.txt @@ -30,7 +30,7 @@ linkgit:gitattributes[5]. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 5ac9cfb0ef..44e7749b10 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -58,14 +58,14 @@ OPTIONS Usually the command automatically creates a commit with a commit log message stating which commit was cherry-picked. This flag applies the change necessary - to cherry-pick the named commit to your working tree, - but does not make the commit. In addition, when this - option is used, your working tree does not have to match + to cherry-pick the named commit to your working tree + and the index, but does not make the commit. In addition, + when this option is used, your index does not have to match the HEAD commit. The cherry-pick is done against the - beginning state of your working tree. + beginning state of your index. + This is useful when cherry-picking more than one commits' -effect to your working tree in a row. +effect to your index in a row. -s:: --signoff:: @@ -74,7 +74,7 @@ effect to your working tree in a row. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt index ef7caf61e1..912601160c 100644 --- a/Documentation/git-cherry.txt +++ b/Documentation/git-cherry.txt @@ -64,7 +64,7 @@ linkgit:git-patch-id[1] Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 7e8b4ff72c..861ce93a49 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -322,7 +322,7 @@ linkgit:git-commit-tree[1] Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net> +Junio C Hamano <gitster@pobox.com> GIT diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index c90421ee7f..b0f20e2392 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -231,7 +231,7 @@ Given a .git/config like this: ; Our diff algorithm [diff] - external = "/usr/local/bin/gnu-diff -u" + external = /usr/local/bin/diff-wrapper renames = true ; Proxy settings diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt index 1ba85a259a..4a9dcd7382 100644 --- a/Documentation/git-count-objects.txt +++ b/Documentation/git-count-objects.txt @@ -27,7 +27,7 @@ OPTIONS Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 2f9b35f622..93b7d2dc99 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -31,6 +31,12 @@ to work with; after that, you need to 'git merge' incremental imports, or any CVS branches, yourself. It is advisable to specify a named remote via -r to separate and protect the incoming branches. +If you intend to set up a shared public repository that all developers can +read/write, or if you want to use linkgit:git-cvsserver[1], then you +probably want to make a bare clone of the imported repository, +and use the clone as the shared repository. +See linkgit:gitcvs-migration[7]. + OPTIONS ------- diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 3310ae25ff..19da87e71d 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -133,6 +133,9 @@ write access to the log file and to the database (see <<dbbackend,Database Backend>>. If you want to offer write access over SSH, the users of course also need write access to the git repository itself. +You also need to ensure that each repository is "bare" (without a git index +file) for `cvs commit` to work. See linkgit:gitcvs-migration[7]. + [[configaccessmethod]] All configuration variables can also be overridden for a specific method of access. Valid method names are "ext" (for SSH access) and "pserver". The diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index 9f6f483186..44aaa4090c 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -136,7 +136,7 @@ will be the smallest number of commits possible. Author ------ Written by Linus Torvalds <torvalds@osdl.org>, but somewhat -butchered by Junio C Hamano <junkio@cox.net>. Later significantly +butchered by Junio C Hamano <gitster@pobox.com>. Later significantly updated by Shawn Pearce <spearce@spearce.org>. Documentation diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 56caeb2d26..5d23985b57 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -49,13 +49,13 @@ include::diff-options.txt[] --stdin:: When '--stdin' is specified, the command does not take <tree-ish> arguments from the command line. Instead, it - reads either one <commit> or a pair of <tree-ish> + reads either one <commit> or a list of <commit> separated with a single space from its standard input. + When a single commit is given on one line of such input, it compares the commit with its parents. The following flags further affects its -behavior. This does not apply to the case where two <tree-ish> -separated with a single space are given. +behavior. The remaining commits, when given, are used as if they are +parents of the first commit. -m:: By default, "git-diff-tree --stdin" does not show @@ -93,11 +93,11 @@ include::pretty-options.txt[] This flag changes the way a merge commit patch is displayed, in a similar way to the '-c' option. It implies the '-c' and '-p' options and further compresses the patch output - by omitting hunks that show differences from only one - parent, or show the same change from all but one parent - for an Octopus merge. When this optimization makes all - hunks disappear, the commit itself and the commit log - message is not shown, just like in any other "empty diff" case. + by omitting uninteresting hunks whose the contents in the parents + have only two variants and the merge result picks one of them + without modification. When all hunks are uninteresting, the commit + itself and the commit log message is not shown, just like in any other + "empty diff" case. --always:: Show the commit itself and the commit log message even diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index 489b2b17e6..4fae7fb5a8 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -45,7 +45,7 @@ linkgit:git-pull[1] Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net> +Junio C Hamano <gitster@pobox.com> Documentation ------------- diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt index 2a7cfb980b..222052fba7 100644 --- a/Documentation/git-fmt-merge-msg.txt +++ b/Documentation/git-fmt-merge-msg.txt @@ -61,7 +61,7 @@ linkgit:git-merge[1] Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 4dafa39a92..ee27eff3b1 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -235,7 +235,7 @@ linkgit:git-am[1], linkgit:git-send-email[1] Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt index cf3dce8a4a..1abcd96c6d 100644 --- a/Documentation/git-hash-object.txt +++ b/Documentation/git-hash-object.txt @@ -37,7 +37,7 @@ OPTIONS Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index f92f3ca186..f282164e9b 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -69,7 +69,7 @@ EXAMPLES Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> GIT --- diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt index d9881fbbbe..8955b71302 100644 --- a/Documentation/git-ls-tree.txt +++ b/Documentation/git-ls-tree.txt @@ -81,7 +81,7 @@ with minimum width of 7 characters. Object size is given only for blobs Author ------ Written by Petr Baudis <pasky@suse.cz> -Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>, +Completely rewritten from scratch by Junio C Hamano <gitster@pobox.com>, another major rewrite by Linus Torvalds <torvalds@osdl.org> Documentation diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt index 183dc1dd75..0b23faee7a 100644 --- a/Documentation/git-mailinfo.txt +++ b/Documentation/git-mailinfo.txt @@ -8,7 +8,7 @@ git-mailinfo - Extracts patch and authorship from a single e-mail message SYNOPSIS -------- -'git-mailinfo' [-k] [-u | --encoding=<encoding>] <msg> <patch> +'git-mailinfo' [-k] [-u | --encoding=<encoding> | -n] <msg> <patch> DESCRIPTION @@ -46,6 +46,9 @@ conversion, even with this flag. from what is specified by i18n.commitencoding, this flag can be used to override it. +-n:: + Disable all charset re-coding of the metadata. + <msg>:: The commit log message extracted from e-mail, usually except the title line which comes from e-mail Subject. @@ -57,7 +60,7 @@ conversion, even with this flag. Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net> +Junio C Hamano <gitster@pobox.com> Documentation diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt index 9a2aedd480..1a0df38d5b 100644 --- a/Documentation/git-mailsplit.txt +++ b/Documentation/git-mailsplit.txt @@ -46,7 +46,7 @@ OPTIONS Author ------ Written by Linus Torvalds <torvalds@osdl.org> -and Junio C Hamano <junkio@cox.net> +and Junio C Hamano <gitster@pobox.com> Documentation diff --git a/Documentation/git-merge-one-file.txt b/Documentation/git-merge-one-file.txt index 5c9ce641ec..546ebe8bf0 100644 --- a/Documentation/git-merge-one-file.txt +++ b/Documentation/git-merge-one-file.txt @@ -18,7 +18,7 @@ to resolve a merge after the trivial merge done with "git-read-tree -m". Author ------ Written by Linus Torvalds <torvalds@osdl.org>, -Junio C Hamano <junkio@cox.net> and Petr Baudis <pasky@suse.cz>. +Junio C Hamano <gitster@pobox.com> and Petr Baudis <pasky@suse.cz>. Documentation -------------- diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 55bc367479..b05e0cee11 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -159,7 +159,7 @@ linkgit:gitattributes[5] Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.txt index 1ddbf00afc..6927eb9950 100644 --- a/Documentation/git-mktree.txt +++ b/Documentation/git-mktree.txt @@ -23,7 +23,7 @@ OPTIONS Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt index ffac3f8f56..83d8e4a9fc 100644 --- a/Documentation/git-name-rev.txt +++ b/Documentation/git-name-rev.txt @@ -38,8 +38,7 @@ OPTIONS Instead of printing both the SHA-1 and the name, print only the name. If given with --tags the usual tag prefix of "tags/" is also omitted from the name, matching the output - of linkgit:git-describe[1] more closely. This option - cannot be combined with --stdin. + of linkgit:git-describe[1] more closely. --no-undefined:: Die with error code != 0 when a reference is undefined, diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt index ffbf93a799..3fb17f9d7f 100644 --- a/Documentation/git-peek-remote.txt +++ b/Documentation/git-peek-remote.txt @@ -39,7 +39,7 @@ OPTIONS Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index d0f1595f7e..c731bdc07e 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -194,7 +194,7 @@ linkgit:git-fetch[1], linkgit:git-merge[1], linkgit:git-config[1] Author ------ Written by Linus Torvalds <torvalds@osdl.org> -and Junio C Hamano <junkio@cox.net> +and Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 89e0049bce..82dd4433f2 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -194,7 +194,7 @@ git push origin master:refs/heads/experimental:: Author ------ -Written by Junio C Hamano <junkio@cox.net>, later rewritten in C +Written by Junio C Hamano <gitster@pobox.com>, later rewritten in C by Linus Torvalds <torvalds@osdl.org> Documentation diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 7166414355..b7e1da000c 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -397,7 +397,7 @@ after each commit, test, and amend the commit if fixes are necessary. Authors ------ -Written by Junio C Hamano <junkio@cox.net> and +Written by Junio C Hamano <gitster@pobox.com> and Johannes E. Schindelin <johannes.schindelin@gmx.de> Documentation diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt index 8492aeacf1..c9c25f3337 100644 --- a/Documentation/git-reflog.txt +++ b/Documentation/git-reflog.txt @@ -94,7 +94,7 @@ them. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.txt index c71d86985e..70810c01d4 100644 --- a/Documentation/git-request-pull.txt +++ b/Documentation/git-request-pull.txt @@ -28,7 +28,7 @@ OPTIONS Author ------ -Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <junkio@cox.net> +Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt index 8030ec4d01..37828e5c5a 100644 --- a/Documentation/git-rerere.txt +++ b/Documentation/git-rerere.txt @@ -204,7 +204,7 @@ conflict. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> GIT --- diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 12ea9b23c5..0b368b39ee 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -195,7 +195,7 @@ $ git add frotz.c <3> Author ------ -Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org> +Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds <torvalds@osdl.org> Documentation -------------- diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 9e273bc5a6..9082fc991b 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -184,7 +184,10 @@ blobs contained in a commit. second ago\}' or '\{1979-02-26 18:30:00\}') to specify the value of the ref at a prior point in time. This suffix may only be used immediately following a ref name and the ref must have an - existing log ($GIT_DIR/logs/<ref>). + existing log ($GIT_DIR/logs/<ref>). Note that this looks up the state + of your *local* ref at a given time; e.g., what was in your local + `master` branch last week. If you want to look at commits made during + certain times, see `--since` and `--until`. * A ref followed by the suffix '@' with an ordinal specification enclosed in a brace pair (e.g. '\{1\}', '\{15\}') to specify @@ -298,9 +301,9 @@ It is the set of commits that are reachable from either one of `r1` or `r2` but not from both. Two other shorthands for naming a set that is formed by a commit -and its parent commits exists. `r1{caret}@` notation means all +and its parent commits exist. The `r1{caret}@` notation means all parents of `r1`. `r1{caret}!` includes commit `r1` but excludes -its all parents. +all of its parents. Here are a handful of examples: @@ -413,7 +416,7 @@ but if $REV is empty, the commit object name from master will be printed. Author ------ Written by Linus Torvalds <torvalds@osdl.org> . -Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org> +Junio C Hamano <gitster@pobox.com> and Pierre Habouzit <madcoder@debian.org> Documentation -------------- diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index 5b49b81386..5fdeaff994 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -43,16 +43,16 @@ OPTIONS -n:: --no-commit:: Usually the command automatically creates a commit with - a commit log message stating which commit was reverted. - This flag applies the change necessary to revert the - named commit to your working tree, but does not make the - commit. In addition, when this option is used, your - working tree does not have to match the HEAD commit. - The revert is done against the beginning state of your - working tree. + a commit log message stating which commit was + reverted. This flag applies the change necessary + to revert the named commit to your working tree + and the index, but does not make the commit. In addition, + when this option is used, your index does not have to match + the HEAD commit. The revert is done against the + beginning state of your index. + This is useful when reverting more than one commits' -effect to your working tree in a row. +effect to your index in a row. -s:: --signoff:: @@ -61,7 +61,7 @@ effect to your working tree in a row. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index de9e8f885f..6f4a2c4306 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -182,7 +182,7 @@ topologically related with each other. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt index baaf2bc8fe..1017391f7c 100644 --- a/Documentation/git-show.txt +++ b/Documentation/git-show.txt @@ -71,7 +71,7 @@ include::i18n.txt[] Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net>. Significantly enhanced by +Junio C Hamano <gitster@pobox.com>. Significantly enhanced by Johannes Schindelin <Johannes.Schindelin@gmx.de>. diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index fef62b16df..6026e8b84b 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -64,7 +64,7 @@ linkgit:gitignore[5] Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net>. +Junio C Hamano <gitster@pobox.com>. Documentation -------------- diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index f4cbd2f212..c350ad0f83 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -448,6 +448,8 @@ svn-remote.<name>.rewriteRoot:: the repository with a public http:// or svn:// URL in the metadata so users of it will see the public URL. +-- + Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps options all affect the metadata generated and used by git-svn; they *must* be set in the configuration file before any history is imported @@ -456,7 +458,6 @@ and these settings should never be changed once they are set. Additionally, only one of these four options can be used per-svn-remote section because they affect the 'git-svn-id:' metadata line. --- BASIC EXAMPLES -------------- @@ -512,7 +513,7 @@ have each person clone that repository with 'git clone': cd project git-init git remote add origin server:/pub/project - git config --add remote.origin.fetch=+refs/remotes/*:refs/remotes/* + git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*' git fetch # Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server) git-svn init http://svn.foo.org/project diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index 3d3a059c5e..5709dee208 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -55,7 +55,7 @@ name is not a symbolic ref, or 128 if another error occurs. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> GIT --- diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 8f40f4bf0d..6cf11ce648 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -247,7 +247,7 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1 Author ------ Written by Linus Torvalds <torvalds@osdl.org>, -Junio C Hamano <junkio@cox.net> and Chris Wright <chrisw@osdl.org>. +Junio C Hamano <gitster@pobox.com> and Chris Wright <chrisw@osdl.org>. Documentation -------------- diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt index d21be41d06..4fd7b5edf9 100644 --- a/Documentation/git-update-server-info.txt +++ b/Documentation/git-update-server-info.txt @@ -47,7 +47,7 @@ info/refs file unless `--force` flag is given. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt index 478f236996..ff704bd93f 100644 --- a/Documentation/git-verify-pack.txt +++ b/Documentation/git-verify-pack.txt @@ -42,7 +42,7 @@ for objects that are deltified. Author ------ -Written by Junio C Hamano <junkio@cox.net> +Written by Junio C Hamano <gitster@pobox.com> Documentation -------------- diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt index f5d39c7870..fb672ea0fc 100644 --- a/Documentation/git-whatchanged.txt +++ b/Documentation/git-whatchanged.txt @@ -67,7 +67,7 @@ git-whatchanged --since="2 weeks ago" \-- gitk:: Author ------ Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <junkio@cox.net> +Junio C Hamano <gitster@pobox.com> Documentation diff --git a/Documentation/git.txt b/Documentation/git.txt index ee96774009..0f55f8005b 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,7 +43,17 @@ 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.5/git.html[documentation for release 1.5.5] +* link:v1.5.6.5/git.html[documentation for release 1.5.6.5] + +* release notes for + link:RelNotes-1.5.6.5.txt[1.5.6.5], + link:RelNotes-1.5.6.4.txt[1.5.6.4], + link:RelNotes-1.5.6.3.txt[1.5.6.3], + link:RelNotes-1.5.6.2.txt[1.5.6.2], + link:RelNotes-1.5.6.1.txt[1.5.6.1], + link:RelNotes-1.5.6.txt[1.5.6]. + +* link:v1.5.5.4/git.html[documentation for release 1.5.5.4] * release notes for link:RelNotes-1.5.5.4.txt[1.5.5.4], @@ -52,8 +62,6 @@ Documentation for older releases are available here: link:RelNotes-1.5.5.1.txt[1.5.5.1], link:RelNotes-1.5.5.txt[1.5.5]. -* link:v1.5.5.4/git.html[documentation for release 1.5.5.4] - * link:v1.5.4.5/git.html[documentation for release 1.5.4.5] * release notes for @@ -77,6 +85,8 @@ Documentation for older releases are available here: link:RelNotes-1.5.3.1.txt[1.5.3.1], link:RelNotes-1.5.3.txt[1.5.3]. +* link:v1.5.2.5/git.html[documentation for release 1.5.2.5] + * release notes for link:RelNotes-1.5.2.5.txt[1.5.2.5], link:RelNotes-1.5.2.4.txt[1.5.2.4], diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 471754eb12..ef06d94ca8 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -450,6 +450,23 @@ String:: variable. +Creating an archive +~~~~~~~~~~~~~~~~~~~ + +`export-subst` +^^^^^^^^^^^^^^ + +If the attribute `export-subst` is set for a file then git will expand +several placeholders when adding this file to an archive. The +expansion depends on the availability of a commit ID, i.e. if +linkgit:git-archive[1] has been given a tree instead of a commit or a +tag then no replacement will be done. The placeholders are the same +as those for the option `--pretty=format:` of linkgit:git-log[1], +except that they need to be wrapped like this: `$Format:PLACEHOLDERS$` +in the file. E.g. the string `$Format:%H$` will be replaced by the +commit hash. + + EXAMPLE ------- @@ -499,22 +516,6 @@ frotz unspecified ---------------------------------------------------------------- -Creating an archive -~~~~~~~~~~~~~~~~~~~ - -`export-subst` -^^^^^^^^^^^^^^ - -If the attribute `export-subst` is set for a file then git will expand -several placeholders when adding this file to an archive. The -expansion depends on the availability of a commit ID, i.e. if -linkgit:git-archive[1] has been given a tree instead of a commit or a -tag then no replacement will be done. The placeholders are the same -as those for the option `--pretty=format:` of linkgit:git-log[1], -except that they need to be wrapped like this: `$Format:PLACEHOLDERS$` -in the file. E.g. the string `$Format:%H$` will be replaced by the -commit hash. - GIT --- diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.txt index 1db3f52945..0325d6759d 100644 --- a/Documentation/gitcvs-migration.txt +++ b/Documentation/gitcvs-migration.txt @@ -143,6 +143,11 @@ work, you must not modify the imported branches; instead, create new branches for your own changes, and merge in the imported branches as necessary. +If you want a shared repository, you will need to make a bare clone +of the imported directory, as described above. Then treat the imported +directory as another development clone for purposes of merging +incremental imports. + Advanced Shared Repository Management ------------------------------------- diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt index 7a76045eb7..d214d4bf9d 100644 --- a/Documentation/howto/rebase-from-internal-branch.txt +++ b/Documentation/howto/rebase-from-internal-branch.txt @@ -1,4 +1,4 @@ -From: Junio C Hamano <junkio@cox.net> +From: Junio C Hamano <gitster@pobox.com> To: git@vger.kernel.org Cc: Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org> Subject: Re: sending changesets from the middle of a git tree diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt index 8d55dfbfae..48c67568d3 100644 --- a/Documentation/howto/rebuild-from-update-hook.txt +++ b/Documentation/howto/rebuild-from-update-hook.txt @@ -1,6 +1,6 @@ Subject: [HOWTO] Using post-update hook Message-ID: <7vy86o6usx.fsf@assigned-by-dhcp.cox.net> -From: Junio C Hamano <junkio@cox.net> +From: Junio C Hamano <gitster@pobox.com> Date: Fri, 26 Aug 2005 18:19:10 -0700 Abstract: In this how-to article, JC talks about how he uses the post-update hook to automate git documentation page diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt index 865a666324..e70d8a31e7 100644 --- a/Documentation/howto/revert-branch-rebase.txt +++ b/Documentation/howto/revert-branch-rebase.txt @@ -1,4 +1,4 @@ -From: Junio C Hamano <junkio@cox.net> +From: Junio C Hamano <gitster@pobox.com> To: git@vger.kernel.org Subject: [HOWTO] Reverting an existing commit Abstract: In this article, JC gives a small real-life example of using diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt index 0d73b31224..6d3eb8ed00 100644 --- a/Documentation/howto/separating-topic-branches.txt +++ b/Documentation/howto/separating-topic-branches.txt @@ -1,4 +1,4 @@ -From: Junio C Hamano <junkio@cox.net> +From: Junio C Hamano <gitster@pobox.com> Subject: Separating topic branches Abstract: In this article, JC describes how to separate topic branches. diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt index 88765b5575..3ef7c0d908 100644 --- a/Documentation/howto/update-hook-example.txt +++ b/Documentation/howto/update-hook-example.txt @@ -1,4 +1,4 @@ -From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com> +From: Junio C Hamano <gitster@pobox.com> and Carl Baldwin <cnb@fc.hp.com> Subject: control access to branches. Date: Thu, 17 Nov 2005 23:55:32 -0800 Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> @@ -68,7 +68,7 @@ function info { # - Branches should only be fast-forwarded. case "$1" in refs/tags/*) - [ -f "$GIT_DIR/$1" ] && + git rev-parse --verify -q "$1" && deny >/dev/null "You can't overwrite an existing tag" ;; refs/heads/*) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index ec37555794..c11d495771 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -30,7 +30,7 @@ This is designed to be as compact as possible. commit <sha1> Author: <author> - Date: <date> + Date: <author date> <title line> @@ -50,9 +50,9 @@ This is designed to be as compact as possible. commit <sha1> Author: <author> - AuthorDate: <date & time> + AuthorDate: <author date> Commit: <committer> - CommitDate: <date & time> + CommitDate: <committer date> <title line> @@ -62,7 +62,7 @@ This is designed to be as compact as possible. From <sha1> <date> From: <author> - Date: <date & time> + Date: <author date> Subject: [PATCH] <title line> <full commit message> @@ -101,6 +101,7 @@ The placeholders are: - '%P': parent hashes - '%p': abbreviated parent hashes - '%an': author name +- '%aN': author name (respecting .mailmap) - '%ae': author email - '%ad': author date - '%aD': author date, RFC2822 style @@ -108,6 +109,7 @@ The placeholders are: - '%at': author date, UNIX timestamp - '%ai': author date, ISO 8601 format - '%cn': committer name +- '%cN': committer name (respecting .mailmap) - '%ce': committer email - '%cd': committer date - '%cD': committer date, RFC2822 style diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 37dd1d61ea..f69260f4c0 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -108,9 +108,9 @@ options may be given. See linkgit:git-diff-files[1] for more options. --cc:: This flag implies the '-c' options and further compresses the - patch output by omitting hunks that show differences from only - one parent, or show the same change from all but one parent for - an Octopus merge. + patch output by omitting uninteresting hunks whose contents in + the parents have only two variants and the merge result picks + one of them without modification. -r:: diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt index 52cdb4c520..7ede1e64e5 100644 --- a/Documentation/technical/api-builtin.txt +++ b/Documentation/technical/api-builtin.txt @@ -4,7 +4,7 @@ builtin API Adding a new built-in --------------------- -There are 4 things to do to add a bulit-in command implementation to +There are 4 things to do to add a built-in command implementation to git: . Define the implementation of the built-in command `foo` with @@ -18,8 +18,8 @@ git: defined in `git.c`. The entry should look like: { "foo", cmd_foo, <options> }, - - where options is the bitwise-or of: ++ +where options is the bitwise-or of: `RUN_SETUP`:: @@ -33,6 +33,12 @@ git: If the standard output is connected to a tty, spawn a pager and feed our output to it. +`NEED_WORK_TREE`:: + + Make sure there is a work tree, i.e. the command cannot act + on bare repositories. + This makes only sense when `RUN_SETUP` is also set. + . Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`. Additionally, if `foo` is a new command, there are 3 more things to do: @@ -41,8 +47,7 @@ Additionally, if `foo` is a new command, there are 3 more things to do: . Write documentation in `Documentation/git-foo.txt`. -. Add an entry for `git-foo` to the list at the end of - `Documentation/cmd-list.perl`. +. Add an entry for `git-foo` to `command-list.txt`. How a built-in is called diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index b7cda94f54..539863b1f9 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -1,6 +1,206 @@ parse-options API ================= -Talk about <parse-options.h> +The parse-options API is used to parse and massage options in git +and to provide a usage help with consistent look. -(Pierre) +Basics +------ + +The argument vector `argv[]` may usually contain mandatory or optional +'non-option arguments', e.g. a filename or a branch, and 'options'. +Options are optional arguments that start with a dash and +that allow to change the behavior of a command. + +* There are basically three types of options: + 'boolean' options, + options with (mandatory) 'arguments' and + options with 'optional arguments' + (i.e. a boolean option that can be adjusted). + +* There are basically two forms of options: + 'Short options' consist of one dash (`-`) and one alphanumeric + character. + 'Long options' begin with two dashes (`\--`) and some + alphanumeric characters. + +* Options are case-sensitive. + Please define 'lower-case long options' only. + +The parse-options API allows: + +* 'sticked' and 'separate form' of options with arguments. + `-oArg` is sticked, `-o Arg` is separate form. + `\--option=Arg` is sticked, `\--option Arg` is separate form. + +* Long options may be 'abbreviated', as long as the abbreviation + is unambiguous. + +* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`. + +* Boolean long options can be 'negated' (or 'unset') by prepending + `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. + +* Options and non-option arguments can clearly be separated using the `\--` + option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that + `\--this-is-a-file` must not be processed as an option. + +Steps to parse options +---------------------- + +. `#include "parse-options.h"` + +. define a NULL-terminated + `static const char * const builtin_foo_usage[]` array + containing alternative usage strings + +. define `builtin_foo_options` array as described below + in section 'Data Structure'. + +. in `cmd_foo(int argc, const char **argv, const char *prefix)` + call + + argc = parse_options(argc, argv, builtin_foo_options, builtin_foo_usage, flags); ++ +`parse_options()` will filter out the processed options of `argv[]` and leave the +non-option arguments in `argv[]`. +`argc` is updated appropriately because of the assignment. ++ +Flags are the bitwise-or of: + +`PARSE_OPT_KEEP_DASHDASH`:: + Keep the `\--` that usually separates options from + non-option arguments. + +`PARSE_OPT_STOP_AT_NON_OPTION`:: + Usually the whole argument vector is massaged and reordered. + Using this flag, processing is stopped at the first non-option + argument. + +Data Structure +-------------- + +The main data structure is an array of the `option` struct, +say `static struct option builtin_add_options[]`. +There are some macros to easily define options: + +`OPT__ABBREV(&int_var)`:: + Add `\--abbrev[=<n>]`. + +`OPT__DRY_RUN(&int_var)`:: + Add `-n, \--dry-run`. + +`OPT__QUIET(&int_var)`:: + Add `-q, \--quiet`. + +`OPT__VERBOSE(&int_var)`:: + Add `-v, \--verbose`. + +`OPT_GROUP(description)`:: + Start an option group. `description` is a short string that + describes the group or an empty string. + Start the description with an upper-case letter. + +`OPT_BOOLEAN(short, long, &int_var, description)`:: + Introduce a boolean option. + `int_var` is incremented on each use. + +`OPT_BIT(short, long, &int_var, description, mask)`:: + Introduce a boolean option. + If used, `int_var` is bitwise-ored with `mask`. + +`OPT_SET_INT(short, long, &int_var, description, integer)`:: + Introduce a boolean option. + If used, set `int_var` to `integer`. + +`OPT_SET_PTR(short, long, &ptr_var, description, ptr)`:: + Introduce a boolean option. + If used, set `ptr_var` to `ptr`. + +`OPT_STRING(short, long, &str_var, arg_str, description)`:: + Introduce an option with string argument. + The string argument is put into `str_var`. + +`OPT_INTEGER(short, long, &int_var, description)`:: + Introduce an option with integer argument. + The integer is put into `int_var`. + +`OPT_DATE(short, long, &int_var, description)`:: + Introduce an option with date argument, see `approxidate()`. + The timestamp is put into `int_var`. + +`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`:: + Introduce an option with argument. + The argument will be fed into the function given by `func_ptr` + and the result will be put into `var`. + See 'Option Callbacks' below for a more elaborate description. + +`OPT_ARGUMENT(long, description)`:: + Introduce a long-option argument that will be kept in `argv[]`. + + +The last element of the array must be `OPT_END()`. + +If not stated otherwise, interpret the arguments as follows: + +* `short` is a character for the short option + (e.g. `\'e\'` for `-e`, use `0` to omit), + +* `long` is a string for the long option + (e.g. `"example"` for `\--example`, use `NULL` to omit), + +* `int_var` is an integer variable, + +* `str_var` is a string variable (`char *`), + +* `arg_str` is the string that is shown as argument + (e.g. `"branch"` will result in `<branch>`). + If set to `NULL`, three dots (`...`) will be displayed. + +* `description` is a short string to describe the effect of the option. + It shall begin with a lower-case letter and a full stop (`.`) shall be + omitted at the end. + +Option Callbacks +---------------- + +The function must be defined in this form: + + int func(const struct option *opt, const char *arg, int unset) + +The callback mechanism is as follows: + +* Inside `funct`, the only interesting member of the structure + given by `opt` is the void pointer `opt->value`. + `\*opt->value` will be the value that is saved into `var`, if you + use `OPT_CALLBACK()`. + For example, do `*(unsigned long *)opt->value = 42;` to get 42 + into an `unsigned long` variable. + +* Return value `0` indicates success and non-zero return + value will invoke `usage_with_options()` and, thus, die. + +* If the user negates the option, `arg` is `NULL` and `unset` is 1. + +Sophisticated option parsing +---------------------------- + +If you need, for example, option callbacks with optional arguments +or without arguments at all, or if you need other special cases, +that are not handled by the macros above, you need to specify the +members of the `option` structure manually. + +This is not covered in this document, but well documented +in `parse-options.h` itself. + +Examples +-------- + +See `test-parse-options.c` and +`builtin-add.c`, +`builtin-clone.c`, +`builtin-commit.c`, +`builtin-fetch.c`, +`builtin-fsck.c`, +`builtin-rm.c` +for real-world examples. diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt index d077683171..9dbedd0a67 100644 --- a/Documentation/technical/api-path-list.txt +++ b/Documentation/technical/api-path-list.txt @@ -1,9 +1,126 @@ path-list API ============= -Talk about <path-list.h>, things like +The path_list API offers a data structure and functions to handle sorted +and unsorted string lists. -* it is not just paths but strings in general; -* the calling sequence. +The name is a bit misleading, a path_list may store not only paths but +strings in general. -(Dscho) +The caller: + +. Allocates and clears a `struct path_list` variable. + +. Initializes the members. You might want to set the flag `strdup_paths` + if the strings should be strdup()ed. For example, this is necessary + when you add something like git_path("..."), since that function returns + a static buffer that will change with the next call to git_path(). ++ +If you need something advanced, you can manually malloc() the `items` +member (you need this if you add things later) and you should set the +`nr` and `alloc` members in that case, too. + +. Adds new items to the list, using `path_list_append` or `path_list_insert`. + +. Can check if a string is in the list using `path_list_has_path` or + `unsorted_path_list_has_path` and get it from the list using + `path_list_lookup` for sorted lists. + +. Can sort an unsorted list using `sort_path_list`. + +. Finally it should free the list using `path_list_clear`. + +Example: + +---- +struct path_list list; +int i; + +memset(&list, 0, sizeof(struct path_list)); +path_list_append("foo", &list); +path_list_append("bar", &list); +for (i = 0; i < list.nr; i++) + printf("%s\n", list.items[i].path) +---- + +NOTE: It is more efficient to build an unsorted list and sort it +afterwards, instead of building a sorted list (`O(n log n)` instead of +`O(n^2)`). ++ +However, if you use the list to check if a certain string was added +already, you should not do that (using unsorted_path_list_has_path()), +because the complexity would be quadratic again (but with a worse factor). + +Functions +--------- + +* General ones (works with sorted and unsorted lists as well) + +`print_path_list`:: + + Dump a path_list to stdout, useful mainly for debugging purposes. It + can take an optional header argument and it writes out the + string-pointer pairs of the path_list, each one in its own line. + +`path_list_clear`:: + + Free a path_list. The `path` pointer of the items will be freed in case + the `strdup_paths` member of the path_list is set. The second parameter + controls if the `util` pointer of the items should be freed or not. + +* Functions for sorted lists only + +`path_list_has_path`:: + + Determine if the path_list has a given string or not. + +`path_list_insert`:: + + Insert a new element to the path_list. The returned pointer can be handy + if you want to write something to the `util` pointer of the + path_list_item containing the just added string. ++ +Since this function uses xrealloc() (which die()s if it fails) if the +list needs to grow, it is safe not to check the pointer. I.e. you may +write `path_list_insert(...)->util = ...;`. + +`path_list_lookup`:: + + Look up a given string in the path_list, returning the containing + path_list_item. If the string is not found, NULL is returned. + +* Functions for unsorted lists only + +`path_list_append`:: + + Append a new string to the end of the path_list. + +`sort_path_list`:: + + Make an unsorted list sorted. + +`unsorted_path_list_has_path`:: + + It's like `path_list_has_path()` but for unsorted lists. ++ +This function needs to look through all items, as opposed to its +counterpart for sorted lists, which performs a binary search. + +Data structures +--------------- + +* `struct path_list_item` + +Represents an item of the list. The `path` member is a pointer to the +string, and you may use the `util` member for any purpose, if you want. + +* `struct path_list` + +Represents the list itself. + +. The array of items are available via the `items` member. +. The `nr` member contains the number of items stored in the list. +. The `alloc` member is used to avoid reallocating at every insertion. + You should not tamper with it. +. Setting the `strdup_paths` member to 1 will strdup() the strings + before adding them, see above. diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt index c364a22c8f..75aa5d4923 100644 --- a/Documentation/technical/api-run-command.txt +++ b/Documentation/technical/api-run-command.txt @@ -30,7 +30,7 @@ Functions start_command() followed by finish_command(). Takes a pointer to a `struct child_process` that specifies the details. -`run_command_v_opt`, `run_command_v_opt_dir`, `run_command_v_opt_cd_env`:: +`run_command_v_opt`, `run_command_v_opt_cd`, `run_command_v_opt_cd_env`:: Convenience functions that encapsulate a sequence of start_command() followed by finish_command(). The argument argv @@ -63,7 +63,7 @@ command to run in a sub-process. The caller: -1. allocates and clears (memset(&chld, '0', sizeof(chld));) a +1. allocates and clears (memset(&chld, 0, sizeof(chld));) a struct child_process variable; 2. initializes the members; 3. calls start_command(); @@ -136,7 +136,7 @@ to produce output that the caller reads. The caller: -1. allocates and clears (memset(&asy, '0', sizeof(asy));) a +1. allocates and clears (memset(&asy, 0, sizeof(asy));) a struct async variable; 2. initializes .proc and .data; 3. calls start_async(); diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 3cabc92e7a..445dca3ffc 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.5.GIT +DEF_VER=v1.5.6.5.GIT LF=' ' @@ -1210,8 +1210,12 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS echo "$$FLAGS" >GIT-CFLAGS; \ fi +# We need to apply sq twice, once to protect from the shell +# that runs GIT-BUILD-OPTIONS, and then again to protect it +# and the first level quoting from the shell that runs "echo". GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS - @echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@ + @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ + @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -1 +1 @@ -Documentation/RelNotes-1.5.6.txt
\ No newline at end of file +Documentation/RelNotes-1.5.6.5.txt
\ No newline at end of file @@ -459,7 +459,9 @@ static void prepare_attr_stack(const char *path, int dirlen) { struct attr_stack *elem, *info; int len; - char pathbuf[PATH_MAX]; + struct strbuf pathbuf; + + strbuf_init(&pathbuf, dirlen+2+strlen(GITATTRIBUTES_FILE)); /* * At the bottom of the attribute stack is the built-in @@ -510,13 +512,14 @@ static void prepare_attr_stack(const char *path, int dirlen) len = strlen(attr_stack->origin); if (dirlen <= len) break; - memcpy(pathbuf, path, dirlen); - memcpy(pathbuf + dirlen, "/", 2); - cp = strchr(pathbuf + len + 1, '/'); + strbuf_reset(&pathbuf); + strbuf_add(&pathbuf, path, dirlen); + strbuf_addch(&pathbuf, '/'); + cp = strchr(pathbuf.buf + len + 1, '/'); strcpy(cp + 1, GITATTRIBUTES_FILE); - elem = read_attr(pathbuf, 0); + elem = read_attr(pathbuf.buf, 0); *cp = '\0'; - elem->origin = strdup(pathbuf); + elem->origin = strdup(pathbuf.buf); elem->prev = attr_stack; attr_stack = elem; debug_push(elem); diff --git a/builtin-cat-file.c b/builtin-cat-file.c index bd343efae7..880e75af5e 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -181,6 +181,7 @@ static int batch_one_object(const char *obj_name, int print_contents) write_or_die(1, contents, size); printf("\n"); fflush(stdout); + free(contents); } return 0; diff --git a/builtin-checkout.c b/builtin-checkout.c index 93ea69bfaa..aec2bc6f8d 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -520,7 +520,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.track = git_branch_track; - argc = parse_options(argc, argv, options, checkout_usage, 0); + argc = parse_options(argc, argv, options, checkout_usage, + PARSE_OPT_KEEP_DASHDASH); if (argc) { arg = argv[0]; if (get_sha1(arg, rev)) diff --git a/builtin-clone.c b/builtin-clone.c index 7190952071..863b22eeb2 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -337,6 +337,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) const struct ref *refs, *head_points_at, *remote_head, *mapped_refs; char branch_top[256], key[256], value[256]; struct strbuf reflog_msg; + struct transport *transport = NULL; struct refspec refspec; @@ -400,6 +401,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (!option_bare) { junk_work_tree = work_tree; + if (safe_create_leading_directories_const(work_tree) < 0) + die("could not create leading directories of '%s'", + work_tree); if (mkdir(work_tree, 0755)) die("could not create work tree dir '%s'.", work_tree); set_git_work_tree(work_tree); @@ -410,11 +414,19 @@ int cmd_clone(int argc, const char **argv, const char *prefix) setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1); + if (safe_create_leading_directories_const(git_dir) < 0) + die("could not create leading directories of '%s'", git_dir); set_git_dir(make_absolute_path(git_dir)); - fprintf(stderr, "Initialize %s\n", git_dir); init_db(option_template, option_quiet ? INIT_DB_QUIET : 0); + /* + * At this point, the config exists, so we do not need the + * environment variable. We actually need to unset it, too, to + * re-enable parsing of the global configs. + */ + unsetenv(CONFIG_ENVIRONMENT); + if (option_reference) setup_reference(git_dir); @@ -447,7 +459,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) refs = clone_local(path, git_dir); else { struct remote *remote = remote_get(argv[0]); - struct transport *transport = transport_get(remote, argv[0]); + transport = transport_get(remote, remote->url[0]); if (!transport->get_refs_list || !transport->fetch) die("Don't know how to clone %s", transport->url); @@ -461,6 +473,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_quiet) transport->verbose = -1; + if (option_upload_pack) + transport_set_option(transport, TRANS_OPT_UPLOADPACK, + option_upload_pack); + refs = transport_get_remote_refs(transport); transport_fetch_refs(transport, refs); } @@ -517,6 +533,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) option_no_checkout = 1; } + if (transport) + transport_unlock_pack(transport); + if (!option_no_checkout) { struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); struct unpack_trees_options opts; diff --git a/builtin-commit.c b/builtin-commit.c index 90200ed643..0c6d1f4f45 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -45,7 +45,8 @@ static enum { COMMIT_PARTIAL, } commit_style; -static char *logfile, *force_author, *template_file; +static const char *logfile, *force_author; +static const char *template_file; static char *edit_message, *use_message; static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; @@ -699,11 +700,14 @@ static int message_is_empty(struct strbuf *sb, int start) } static int parse_and_validate_options(int argc, const char *argv[], - const char * const usage[]) + const char * const usage[], + const char *prefix) { int f = 0; argc = parse_options(argc, argv, builtin_commit_options, usage, 0); + logfile = parse_options_fix_filename(prefix, logfile); + template_file = parse_options_fix_filename(prefix, template_file); if (logfile || message.len || use_message) use_editor = 0; @@ -813,7 +817,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) if (wt_status_use_color == -1) wt_status_use_color = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_status_usage); + argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix); index_file = prepare_index(argc, argv, prefix); @@ -864,12 +868,8 @@ static void print_summary(const char *prefix, const unsigned char *sha1) int git_commit_config(const char *k, const char *v, void *cb) { - if (!strcmp(k, "commit.template")) { - if (!v) - return config_error_nonbool(v); - template_file = xstrdup(v); - return 0; - } + if (!strcmp(k, "commit.template")) + return git_config_string(&template_file, k, v); return git_status_config(k, v, cb); } @@ -910,7 +910,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) git_config(git_commit_config, NULL); - argc = parse_and_validate_options(argc, argv, builtin_commit_usage); + argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix); index_file = prepare_index(argc, argv, prefix); diff --git a/builtin-describe.c b/builtin-describe.c index 3da99c1d06..e515f9ca9b 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -204,7 +204,7 @@ static void describe(const char *arg, int last_one) */ display_name(n); if (longformat) - show_suffix(0, n->tag->tagged->sha1); + show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1); printf("\n"); return; } diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index de1e8d1365..6e98cafd08 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -309,7 +309,8 @@ done: } flushes--; } - return retval; + /* it is no error to fetch into a completely empty repo */ + return count ? retval : 0; } static struct commit_list *complete; diff --git a/builtin-fetch.c b/builtin-fetch.c index e81ee2d02b..97fdc51e31 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -181,9 +181,9 @@ static int s_update_ref(const char *action, lock = lock_any_ref_for_update(ref->name, check_old ? ref->old_sha1 : NULL, 0); if (!lock) - return 1; + return 2; if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) - return 1; + return 2; return 0; } @@ -233,10 +233,12 @@ static int update_local_ref(struct ref *ref, if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { - sprintf(display, "- %-*s %-*s -> %s", + int r; + r = s_update_ref("updating tag", ref, 0); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, - pretty_ref); - return s_update_ref("updating tag", ref, 0); + pretty_ref, r ? " (unable to update local ref)" : ""); + return r; } current = lookup_commit_reference_gently(ref->old_sha1, 1); @@ -244,6 +246,7 @@ static int update_local_ref(struct ref *ref, if (!current || !updated) { const char *msg; const char *what; + int r; if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; what = "[new tag]"; @@ -253,27 +256,36 @@ static int update_local_ref(struct ref *ref, what = "[new branch]"; } - sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what, - REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref(msg, ref, 0); + r = s_update_ref(msg, ref, 0); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', + SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, + r ? " (unable to update local ref)" : ""); + return r; } if (in_merge_bases(current, &updated, 1)) { char quickref[83]; + int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, " %-*s %-*s -> %s", SUMMARY_WIDTH, quickref, - REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref("fast forward", ref, 1); + r = s_update_ref("fast forward", ref, 1); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', + SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, + pretty_ref, r ? " (unable to update local ref)" : ""); + return r; } else if (force || ref->force) { char quickref[84]; + int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, "+ %-*s %-*s -> %s (forced update)", - SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref("forced-update", ref, 1); + r = s_update_ref("forced-update", ref, 1); + sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', + SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, + pretty_ref, + r ? "unable to update local ref" : "forced update"); + return r; } else { sprintf(display, "! %-*s %-*s -> %s (non fast forward)", SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, @@ -282,7 +294,8 @@ static int update_local_ref(struct ref *ref, } } -static int store_updated_refs(const char *url, struct ref *ref_map) +static int store_updated_refs(const char *url, const char *remote_name, + struct ref *ref_map) { FILE *fp; struct commit *commit; @@ -368,6 +381,10 @@ static int store_updated_refs(const char *url, struct ref *ref_map) } } fclose(fp); + if (rc & 2) + error("some local refs could not be updated; try running\n" + " 'git remote prune %s' to remove any old, conflicting " + "branches", remote_name); return rc; } @@ -438,7 +455,9 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) if (ret) ret = transport_fetch_refs(transport, ref_map); if (!ret) - ret |= store_updated_refs(transport->url, ref_map); + ret |= store_updated_refs(transport->url, + transport->remote->name, + ref_map); transport_unlock_pack(transport); return ret; } diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 07d9c57212..fef93d7488 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -234,6 +234,13 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob name++; if (!strcmp(name, "tag")) v->s = tag->tag; + else if (!strcmp(name, "type") && tag->tagged) + v->s = typename(tag->tagged->type); + else if (!strcmp(name, "object") && tag->tagged) { + char *s = xmalloc(41); + strcpy(s, sha1_to_hex(tag->tagged->sha1)); + v->s = s; + } } } diff --git a/builtin-grep.c b/builtin-grep.c index ef299108f5..d8b06ce810 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -427,33 +427,35 @@ static int grep_tree(struct grep_opt *opt, const char **paths, struct name_entry entry; char *down; int tn_len = strlen(tree_name); - char *path_buf = xmalloc(PATH_MAX + tn_len + 100); + struct strbuf pathbuf; + + strbuf_init(&pathbuf, PATH_MAX + tn_len); if (tn_len) { - tn_len = sprintf(path_buf, "%s:", tree_name); - down = path_buf + tn_len; - strcat(down, base); - } - else { - down = path_buf; - strcpy(down, base); + strbuf_add(&pathbuf, tree_name, tn_len); + strbuf_addch(&pathbuf, ':'); + tn_len = pathbuf.len; } - len = strlen(path_buf); + strbuf_addstr(&pathbuf, base); + len = pathbuf.len; while (tree_entry(tree, &entry)) { - strcpy(path_buf + len, entry.path); + int te_len = tree_entry_len(entry.path, entry.sha1); + pathbuf.len = len; + strbuf_add(&pathbuf, entry.path, te_len); if (S_ISDIR(entry.mode)) /* Match "abc/" against pathspec to * decide if we want to descend into "abc" * directory. */ - strcpy(path_buf + len + tree_entry_len(entry.path, entry.sha1), "/"); + strbuf_addch(&pathbuf, '/'); + down = pathbuf.buf + tn_len; if (!pathspec_matches(paths, down)) ; else if (S_ISREG(entry.mode)) - hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len); + hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; @@ -469,6 +471,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, free(data); } } + strbuf_release(&pathbuf); return hit; } @@ -495,7 +498,7 @@ static int grep_object(struct grep_opt *opt, const char **paths, } static const char builtin_grep_usage[] = -"git-grep <option>* <rev>* [-e] <pattern> [<path>...]"; +"git-grep <option>* [-e] <pattern> <rev>* [[--] <path>...]"; static const char emsg_invalid_context_len[] = "%s: invalid context length argument"; diff --git a/builtin-init-db.c b/builtin-init-db.c index e23b8438c7..c68a3b1e74 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -127,6 +127,8 @@ static void copy_templates(const char *template_dir) template_dir = strbuf_detach(&d, NULL); } } + if (!template_dir[0]) + return; strcpy(template_path, template_dir); template_len = strlen(template_path); if (template_path[template_len-1] != '/') { diff --git a/builtin-log.c b/builtin-log.c index 9817d6fbeb..430d87661e 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -234,12 +234,8 @@ static int git_log_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "format.pretty")) return git_config_string(&fmt_pretty, var, value); - if (!strcmp(var, "format.subjectprefix")) { - if (!value) - config_error_nonbool(var); - fmt_patch_subject_prefix = xstrdup(value); - return 0; - } + if (!strcmp(var, "format.subjectprefix")) + return git_config_string(&fmt_patch_subject_prefix, var, value); if (!strcmp(var, "log.date")) return git_config_string(&default_date_mode, var, value); if (!strcmp(var, "log.showroot")) { @@ -360,7 +356,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); ret = show_object(o->sha1, 1, &rev); - objects[i].item = (struct object *)t->tagged; + objects[i].item = parse_object(t->tagged->sha1); i--; break; } @@ -489,12 +485,8 @@ static int git_format_config(const char *var, const char *value, void *cb) add_header(value); return 0; } - if (!strcmp(var, "format.suffix")) { - if (!value) - return config_error_nonbool(var); - fmt_patch_suffix = xstrdup(value); - return 0; - } + if (!strcmp(var, "format.suffix")) + return git_config_string(&fmt_patch_suffix, var, value); if (!strcmp(var, "format.cc")) { if (!value) return config_error_nonbool(var); diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 97c1ff9744..13f0502b9e 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -334,7 +334,9 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over return 1; if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) { for (i = 0; header[i]; i++) { - if (!memcmp("Subject: ", header[i], 9)) { + if (!memcmp("Subject", header[i], 7)) { + if (!hdr_data[i]) + hdr_data[i] = xmalloc(linesize + 20); if (! handle_header(line, hdr_data[i], 0)) { return 1; } @@ -812,6 +814,7 @@ static void handle_body(void) np - newline); if (!handle_boundary()) return; + len = strlen(line); } /* Unwrap transfer encoding */ @@ -959,7 +962,7 @@ static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, } static const char mailinfo_usage[] = - "git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info"; + "git-mailinfo [-k] [-u | --encoding=<encoding> | -n] msg patch <mail >info"; int cmd_mailinfo(int argc, const char **argv, const char *prefix) { diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 4aa28a1bab..43bf6aa45e 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -481,15 +481,6 @@ static char *unique_path(const char *path, const char *branch) return newpath; } -static int mkdir_p(const char *path, unsigned long mode) -{ - /* path points to cache entries, so xstrdup before messing with it */ - char *buf = xstrdup(path); - int result = safe_create_leading_directories(buf); - free(buf); - return result; -} - static void flush_buffer(int fd, const char *buf, unsigned long size) { while (size > 0) { @@ -512,7 +503,7 @@ static int make_room_for_path(const char *path) int status; const char *msg = "failed to create path '%s'%s"; - status = mkdir_p(path, 0777); + status = safe_create_leading_directories_const(path); if (status) { if (status == -3) { /* something else exists */ @@ -583,7 +574,7 @@ static void update_file_flags(const unsigned char *sha, close(fd); } else if (S_ISLNK(mode)) { char *lnk = xmemdupz(buf, size); - mkdir_p(path, 0777); + safe_create_leading_directories_const(path); unlink(path); symlink(lnk, path); free(lnk); diff --git a/builtin-name-rev.c b/builtin-name-rev.c index f153da012f..5352bc87b9 100644 --- a/builtin-name-rev.c +++ b/builtin-name-rev.c @@ -176,6 +176,48 @@ static char const * const name_rev_usage[] = { NULL }; +static void name_rev_line(char *p, struct name_ref_data *data) +{ + int forty = 0; + char *p_start; + for (p_start = p; *p; p++) { +#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) + if (!ishex(*p)) + forty = 0; + else if (++forty == 40 && + !ishex(*(p+1))) { + unsigned char sha1[40]; + const char *name = NULL; + char c = *(p+1); + int p_len = p - p_start + 1; + + forty = 0; + + *(p+1) = 0; + if (!get_sha1(p - 39, sha1)) { + struct object *o = + lookup_object(sha1); + if (o) + name = get_rev_name(o); + } + *(p+1) = c; + + if (!name) + continue; + + if (data->name_only) + printf("%.*s%s", p_len - 40, p_start, name); + else + printf("%.*s (%s)", p_len, p_start, name); + p_start = p + 1; + } + } + + /* flush */ + if (p_start != p) + fwrite(p_start, p - p_start, 1, stdout); +} + int cmd_name_rev(int argc, const char **argv, const char *prefix) { struct object_array revs = { 0, 0, NULL }; @@ -234,47 +276,12 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) if (transform_stdin) { char buffer[2048]; - char *p, *p_start; while (!feof(stdin)) { - int forty = 0; - p = fgets(buffer, sizeof(buffer), stdin); + char *p = fgets(buffer, sizeof(buffer), stdin); if (!p) break; - - for (p_start = p; *p; p++) { -#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) - if (!ishex(*p)) - forty = 0; - else if (++forty == 40 && - !ishex(*(p+1))) { - unsigned char sha1[40]; - const char *name = NULL; - char c = *(p+1); - - forty = 0; - - *(p+1) = 0; - if (!get_sha1(p - 39, sha1)) { - struct object *o = - lookup_object(sha1); - if (o) - name = get_rev_name(o); - } - *(p+1) = c; - - if (!name) - continue; - - fwrite(p_start, p - p_start + 1, 1, stdout); - printf(" (%s)", name); - p_start = p + 1; - } - } - - /* flush */ - if (p_start != p) - fwrite(p_start, p - p_start, 1, stdout); + name_rev_line(p, &data); } } else if (all) { int i, max; diff --git a/builtin-rerere.c b/builtin-rerere.c index 5c811423cc..85222d9bc5 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -43,7 +43,7 @@ static void read_rr(struct path_list *rr) ; /* do nothing */ if (i == sizeof(buf)) die("filename too long"); - path_list_insert(buf, rr)->util = xstrdup(name); + path_list_insert(buf, rr)->util = name; } fclose(in); } diff --git a/builtin-reset.c b/builtin-reset.c index f34acb1915..a0321694c5 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -194,8 +194,40 @@ int cmd_reset(int argc, const char **argv, const char *prefix) reflog_action = args_to_str(argv); setenv("GIT_REFLOG_ACTION", reflog_action, 0); - if (i < argc && strcmp(argv[i], "--")) - rev = argv[i++]; + /* + * Possible arguments are: + * + * git reset [-opts] <rev> <paths>... + * git reset [-opts] <rev> -- <paths>... + * git reset [-opts] -- <paths>... + * git reset [-opts] <paths>... + * + * At this point, argv[i] points immediately after [-opts]. + */ + + if (i < argc) { + if (!strcmp(argv[i], "--")) { + i++; /* reset to HEAD, possibly with paths */ + } else if (i + 1 < argc && !strcmp(argv[i+1], "--")) { + rev = argv[i]; + i += 2; + } + /* + * Otherwise, argv[i] could be either <rev> or <paths> and + * has to be unambigous. + */ + else if (!get_sha1(argv[i], sha1)) { + /* + * Ok, argv[i] looks like a rev; it should not + * be a filename. + */ + verify_non_filename(prefix, argv[i]); + rev = argv[i++]; + } else { + /* Otherwise we treat this as a filename */ + verify_filename(prefix, argv[i]); + } + } if (get_sha1(rev, sha1)) die("Failed to resolve '%s' as a valid ref.", rev); @@ -205,9 +237,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix) die("Could not parse object '%s'.", rev); hashcpy(sha1, commit->object.sha1); - if (i < argc && !strcmp(argv[i], "--")) - i++; - /* git reset tree [--] paths... can be used to * load chosen paths from the tree into the index without * affecting the working tree nor HEAD. */ diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 83a7b1349e..39ec61c428 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -597,6 +597,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); + quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; @@ -628,10 +629,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) read_revisions_from_stdin(&revs); continue; } - if (!strcmp(arg, "--quiet")) { - quiet = 1; - continue; - } usage(rev_list_usage); } diff --git a/builtin-revert.c b/builtin-revert.c index 0270f9b85a..bde28b2c4d 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -180,7 +180,7 @@ static void set_author_ident_env(const char *message) email++; timestamp = strchr(email, '>'); if (!timestamp) - die ("Could not extract author email from %s", + die ("Could not extract author time from %s", sha1_to_hex(commit->object.sha1)); *timestamp = '\0'; for (timestamp++; *timestamp && isspace(*timestamp); diff --git a/builtin-rm.c b/builtin-rm.c index 22c9bd1c6c..abdab7f001 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -146,11 +146,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); - newfd = hold_locked_index(&lock_file, 1); - - if (read_cache() < 0) - die("index file corrupt"); - argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); @@ -158,6 +153,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!index_only) setup_work_tree(); + newfd = hold_locked_index(&lock_file, 1); + + if (read_cache() < 0) + die("index file corrupt"); + pathspec = get_pathspec(prefix, argv); seen = NULL; for (i = 0; pathspec[i] ; i++) diff --git a/builtin-send-pack.c b/builtin-send-pack.c index d76260c09e..a708d0af48 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -226,8 +226,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref) if (args.verbose) fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst); if (ref->deletion) { - if (delete_ref(rs.dst, NULL)) - error("Failed to delete"); + delete_ref(rs.dst, NULL); } else update_ref("update by push", rs.dst, ref->new_sha1, NULL, 0, 0); diff --git a/builtin-tag.c b/builtin-tag.c index e675206de3..3bd019cc56 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -260,7 +260,7 @@ static int git_tag_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "user.signingkey")) { if (!value) - return config_error_nonbool(value); + return config_error_nonbool(var); set_signingkey(value); return 0; } @@ -385,7 +385,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) int annotate = 0, sign = 0, force = 0, lines = 0, list = 0, delete = 0, verify = 0; - char *msgfile = NULL, *keyid = NULL; + const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct option options[] = { OPT_BOOLEAN('l', NULL, &list, "list tag names"), @@ -411,6 +411,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) git_config(git_tag_config, NULL); argc = parse_options(argc, argv, options, git_tag_usage, 0); + msgfile = parse_options_fix_filename(prefix, msgfile); if (keyid) { sign = 1; diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c index 48ae09e9b5..371400d49a 100644 --- a/builtin-upload-archive.c +++ b/builtin-upload-archive.c @@ -30,7 +30,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix) if (argc != 2) usage(upload_archive_usage); - if (strlen(argv[1]) > sizeof(buf)) + if (strlen(argv[1]) + 1 > sizeof(buf)) die("insanely long repository name"); strcpy(buf, argv[1]); /* enter-repo smudges its argument */ @@ -396,7 +396,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ #define REFRESH_QUIET 0x0004 /* be quiet about it */ #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ -#define REFRESH_IGNORE_SUBMODULES 0x0008 /* ignore submodules */ +#define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */ extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen); struct lock_file { @@ -518,6 +518,7 @@ enum sharedrepo { int git_config_perm(const char *var, const char *value); int adjust_shared_perm(const char *path); int safe_create_leading_directories(char *path); +int safe_create_leading_directories_const(const char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { @@ -525,6 +526,7 @@ static inline int is_absolute_path(const char *path) } const char *make_absolute_path(const char *path); const char *make_nonrelative_path(const char *path); +const char *make_relative_path(const char *abs, const char *base); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); @@ -694,8 +696,6 @@ extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, ch extern int server_supports(const char *feature); extern struct packed_git *parse_pack_index(unsigned char *sha1); -extern struct packed_git *parse_pack_index_file(const unsigned char *sha1, - const char *idx_path); extern void prepare_packed_git(void); extern void reprepare_packed_git(void); diff --git a/combine-diff.c b/combine-diff.c index 588c58bc55..9f80a1c5e3 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -84,6 +84,7 @@ struct sline { /* bit 0 up to (N-1) are on if the parent has this line (i.e. * we did not change it). * bit N is used for "interesting" lines, including context. + * bit (N+1) is used for "do not show deletion before this". */ unsigned long flag; unsigned long *p_lno; @@ -308,6 +309,7 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent) { unsigned long all_mask = (1UL<<num_parent) - 1; unsigned long mark = (1UL<<num_parent); + unsigned long no_pre_delete = (2UL<<num_parent); unsigned long i; /* Two groups of interesting lines may have a short gap of @@ -329,7 +331,7 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent) /* Paint a few lines before the first interesting line. */ while (j < i) - sline[j++].flag |= mark; + sline[j++].flag |= mark | no_pre_delete; again: /* we know up to i is to be included. where does the @@ -502,6 +504,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int use_color) { unsigned long mark = (1UL<<num_parent); + unsigned long no_pre_delete = (2UL<<num_parent); int i; unsigned long lno = 0; const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO); @@ -581,7 +584,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int j; unsigned long p_mask; sl = &sline[lno++]; - ll = sl->lost_head; + ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head; while (ll) { fputs(c_old, stdout); for (j = 0; j < num_parent; j++) { @@ -428,8 +428,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) /* Mark them and clear the indegree */ for (next = orig; next; next = next->next) { struct commit *commit = next->item; - commit->object.flags |= TOPOSORT; - commit->indegree = 0; + commit->indegree = 1; } /* update the indegree */ @@ -438,7 +437,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) while (parents) { struct commit *parent = parents->item; - if (parent->object.flags & TOPOSORT) + if (parent->indegree) parent->indegree++; parents = parents->next; } @@ -456,7 +455,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) for (next = orig; next; next = next->next) { struct commit *commit = next->item; - if (!commit->indegree) + if (commit->indegree == 1) insert = &commit_list_insert(commit, insert)->next; } @@ -478,7 +477,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) for (parents = commit->parents; parents ; parents = parents->next) { struct commit *parent=parents->item; - if (!(parent->object.flags & TOPOSORT)) + if (!parent->indegree) continue; /* @@ -486,7 +485,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) * when all their children have been emitted thereby * guaranteeing topological order. */ - if (!--parent->indegree) { + if (--parent->indegree == 1) { if (!lifo) insert_by_date(parent, &work); else @@ -497,7 +496,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) * work_item is a commit all of whose children * have already been emitted. we can emit it now. */ - commit->object.flags &= ~TOPOSORT; + commit->indegree = 0; *pptr = work_item; pptr = &work_item->next; } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2141b6b6ba..72f02f208f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -45,6 +45,11 @@ # git@vger.kernel.org # +case "$COMP_WORDBREAKS" in +*:*) : great ;; +*) COMP_WORDBREAKS="$COMP_WORDBREAKS:" +esac + __gitdir () { if [ -z "$1" ]; then @@ -114,9 +119,20 @@ __git_ps1 () fi } +__gitcomp_1 () +{ + local c IFS=' '$'\t'$'\n' + for c in $1; do + case "$c$2" in + --*=*) printf %s$'\n' "$c$2" ;; + *.) printf %s$'\n' "$c$2" ;; + *) printf %s$'\n' "$c$2 " ;; + esac + done +} + __gitcomp () { - local all c s=$'\n' IFS=' '$'\t'$'\n' local cur="${COMP_WORDS[COMP_CWORD]}" if [ $# -gt 2 ]; then cur="$3" @@ -124,21 +140,14 @@ __gitcomp () case "$cur" in --*=) COMPREPLY=() - return ;; *) - for c in $1; do - case "$c$4" in - --*=*) all="$all$c$4$s" ;; - *.) all="$all$c$4$s" ;; - *) all="$all$c$4 $s" ;; - esac - done + local IFS=$'\n' + COMPREPLY=($(compgen -P "$2" \ + -W "$(__gitcomp_1 "$1" "$4")" \ + -- "$cur")) ;; esac - IFS=$s - COMPREPLY=($(compgen -P "$2" -W "$all" -- "$cur")) - return } __git_heads () @@ -290,9 +299,23 @@ __git_complete_file () ls="$ref" ;; esac + + case "$COMP_WORDBREAKS" in + *:*) : great ;; + *) pfx="$ref:$pfx" ;; + esac + + local IFS=$'\n' COMPREPLY=($(compgen -P "$pfx" \ -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \ - | sed '/^100... blob /s,^.* ,, + | sed '/^100... blob /{ + s,^.* ,, + s,$, , + } + /^120000 blob /{ + s,^.* ,, + s,$, , + } /^040000 tree /{ s,^.* ,, s,$,/, @@ -320,9 +343,6 @@ __git_complete_revlist () cur="${cur#*..}" __gitcomp "$(__git_refs)" "$pfx" "$cur" ;; - *.) - __gitcomp "$cur." - ;; *) __gitcomp "$(__git_refs)" ;; @@ -451,6 +471,18 @@ __git_find_subcommand () done } +__git_has_doubledash () +{ + local c=1 + while [ $c -lt $COMP_CWORD ]; do + if [ "--" = "${COMP_WORDS[c]}" ]; then + return 0 + fi + c=$((++c)) + done + return 1 +} + __git_whitespacelist="nowarn warn error error-all strip" _git_am () @@ -497,6 +529,8 @@ _git_apply () _git_add () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) @@ -511,6 +545,8 @@ _git_add () _git_bisect () { + __git_has_doubledash && return + local subcommands="start bad good reset visualize replay log" local subcommand="$(__git_find_subcommand "$subcommands")" if [ -z "$subcommand" ]; then @@ -613,6 +649,8 @@ _git_cherry_pick () _git_commit () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) @@ -632,6 +670,8 @@ _git_describe () _git_diff () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) @@ -671,7 +711,12 @@ _git_fetch () *) case "$cur" in *:*) - __gitcomp "$(__git_refs)" "" "${cur#*:}" + local pfx="" + case "$COMP_WORDBREAKS" in + *:*) : great ;; + *) pfx="${cur%%:*}:" ;; + esac + __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}" ;; *) local remote @@ -734,6 +779,8 @@ _git_ls_tree () _git_log () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --pretty=*) @@ -761,6 +808,7 @@ _git_log () --pretty= --name-status --name-only --raw --not --all --left-right --cherry-pick + --graph " return ;; @@ -841,7 +889,14 @@ _git_push () git-push) remote="${COMP_WORDS[1]}" ;; git) remote="${COMP_WORDS[2]}" ;; esac - __gitcomp "$(__git_refs "$remote")" "" "${cur#*:}" + + local pfx="" + case "$COMP_WORDBREAKS" in + *:*) : great ;; + *) pfx="${cur%%:*}:" ;; + esac + + __gitcomp "$(__git_refs "$remote")" "$pfx" "${cur#*:}" ;; +*) __gitcomp "$(__git_refs)" + "${cur#+}" @@ -1084,6 +1139,8 @@ _git_remote () _git_reset () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) @@ -1096,6 +1153,8 @@ _git_reset () _git_shortlog () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --*) @@ -1142,6 +1201,8 @@ _git_stash () _git_submodule () { + __git_has_doubledash && return + local subcommands="add status init update" if [ -z "$(__git_find_subcommand "$subcommands")" ]; then local cur="${COMP_WORDS[COMP_CWORD]}" @@ -1348,6 +1409,8 @@ _git () _gitk () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" local g="$(git rev-parse --git-dir 2>/dev/null)" local merge="" @@ -319,8 +319,8 @@ static int apply_filter(const char *path, const char *src, size_t len, static struct convert_driver { const char *name; struct convert_driver *next; - char *smudge; - char *clean; + const char *smudge; + const char *clean; } *user_convert, **user_convert_tail; static int read_convert_config(const char *var, const char *value, void *cb) @@ -358,19 +358,12 @@ static int read_convert_config(const char *var, const char *value, void *cb) * The command-line will not be interpolated in any way. */ - if (!strcmp("smudge", ep)) { - if (!value) - return config_error_nonbool(var); - drv->smudge = strdup(value); - return 0; - } + if (!strcmp("smudge", ep)) + return git_config_string(&drv->smudge, var, value); + + if (!strcmp("clean", ep)) + return git_config_string(&drv->clean, var, value); - if (!strcmp("clean", ep)) { - if (!value) - return config_error_nonbool(var); - drv->clean = strdup(value); - return 0; - } return 0; } @@ -576,7 +569,7 @@ int convert_to_git(const char *path, const char *src, size_t len, struct git_attr_check check[3]; int crlf = CRLF_GUESS; int ident = 0, ret = 0; - char *filter = NULL; + const char *filter = NULL; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { @@ -606,7 +599,7 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc struct git_attr_check check[3]; int crlf = CRLF_GUESS; int ident = 0, ret = 0; - char *filter = NULL; + const char *filter = NULL; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { @@ -694,23 +694,47 @@ static void kill_some_children(int signo, unsigned start, unsigned stop) } } +static void check_dead_children(void) +{ + unsigned spawned, reaped, deleted; + + spawned = children_spawned; + reaped = children_reaped; + deleted = children_deleted; + + while (deleted < reaped) { + pid_t pid = dead_child[deleted % MAX_CHILDREN]; + const char *dead = pid < 0 ? " (with error)" : ""; + + if (pid < 0) + pid = -pid; + + /* XXX: Custom logging, since we don't wanna getpid() */ + if (verbose) { + if (log_syslog) + syslog(LOG_INFO, "[%d] Disconnected%s", + pid, dead); + else + fprintf(stderr, "[%d] Disconnected%s\n", + pid, dead); + } + remove_child(pid, deleted, spawned); + deleted++; + } + children_deleted = deleted; +} + static void check_max_connections(void) { for (;;) { int active; - unsigned spawned, reaped, deleted; + unsigned spawned, deleted; + + check_dead_children(); spawned = children_spawned; - reaped = children_reaped; deleted = children_deleted; - while (deleted < reaped) { - pid_t pid = dead_child[deleted % MAX_CHILDREN]; - remove_child(pid, deleted, spawned); - deleted++; - } - children_deleted = deleted; - active = spawned - deleted; if (active <= max_connections) break; @@ -760,18 +784,10 @@ static void child_handler(int signo) if (pid > 0) { unsigned reaped = children_reaped; + if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) + pid = -pid; dead_child[reaped % MAX_CHILDREN] = pid; children_reaped = reaped + 1; - /* XXX: Custom logging, since we don't wanna getpid() */ - if (verbose) { - const char *dead = ""; - if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) - dead = " (with error)"; - if (log_syslog) - syslog(LOG_INFO, "[%d] Disconnected%s", pid, dead); - else - fprintf(stderr, "[%d] Disconnected%s\n", pid, dead); - } continue; } break; @@ -928,8 +944,18 @@ static int service_loop(int socknum, int *socklist) for (;;) { int i; + int timeout; - if (poll(pfd, socknum, -1) < 0) { + /* + * This 1-sec timeout could lead to idly looping but it is + * here so that children culled in child_handler() are reported + * without too much delay. We could probably set up a pipe + * to ourselves that we poll, and write to the fd from child_handler() + * to wake us up (and consume it when the poll() returns... + */ + timeout = (children_spawned != children_deleted) ? 1000 : -1; + i = poll(pfd, socknum, timeout); + if (i < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", strerror(errno)); @@ -937,6 +963,10 @@ static int service_loop(int socknum, int *socklist) } continue; } + if (i == 0) { + check_dead_children(); + continue; + } for (i = 0; i < socknum; i++) { if (pfd[i].revents & POLLIN) { @@ -682,10 +682,8 @@ static void date_am(struct tm *tm, int *num) static void date_never(struct tm *tm, int *num) { - tm->tm_mon = tm->tm_wday = tm->tm_yday - = tm->tm_hour = tm->tm_min = tm->tm_sec = 0; - tm->tm_year = 70; - tm->tm_mday = 1; + time_t n = 0; + localtime_r(&n, tm); } static const struct special { diff --git a/diff-lib.c b/diff-lib.c index b17722d66a..e7eaff9a68 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -171,7 +171,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (silent_on_removed) continue; diff_addremove(&revs->diffopt, '-', ce->ce_mode, - ce->sha1, ce->name, NULL); + ce->sha1, ce->name); continue; } changed = ce_match_stat(ce, &st, ce_option); @@ -184,7 +184,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), - ce->name, NULL); + ce->name); } diffcore_std(&revs->diffopt); @@ -208,7 +208,7 @@ static void diff_index_show_file(struct rev_info *revs, const unsigned char *sha1, unsigned int mode) { diff_addremove(&revs->diffopt, prefix[0], mode, - sha1, ce->name, NULL); + sha1, ce->name); } static int get_stat_data(struct cache_entry *ce, @@ -312,7 +312,7 @@ static int show_modified(struct oneway_unpack_data *cbdata, return 0; diff_change(&revs->diffopt, oldmode, mode, - old->sha1, sha1, old->name, NULL); + old->sha1, sha1, old->name); return 0; } @@ -131,10 +131,6 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v */ int git_diff_ui_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, "diff.renamelimit")) { - diff_rename_limit_default = git_config_int(var, value); - return 0; - } if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { diff_use_color_default = git_config_colorbool(var, value, -1); return 0; @@ -153,12 +149,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_auto_refresh_index = git_config_bool(var, value); return 0; } - if (!strcmp(var, "diff.external")) { - if (!value) - return config_error_nonbool(var); - external_diff_cmd_cfg = xstrdup(value); - return 0; - } + if (!strcmp(var, "diff.external")) + return git_config_string(&external_diff_cmd_cfg, var, value); if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); @@ -171,6 +163,11 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) int git_diff_basic_config(const char *var, const char *value, void *cb) { + if (!strcmp(var, "diff.renamelimit")) { + diff_rename_limit_default = git_config_int(var, value); + return 0; + } + if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); if (!value) @@ -514,9 +511,15 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) { + int has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + fputs(set, file); fwrite(line, len, 1, file); fputs(reset, file); + if (has_trailing_newline) + fputc('\n', file); } static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) @@ -1144,12 +1147,14 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) char *err; if (line[0] == '+') { + unsigned bad; data->lineno++; - data->status = check_and_emit_line(line + 1, len - 1, + bad = check_and_emit_line(line + 1, len - 1, data->ws_rule, NULL, NULL, NULL, NULL); - if (!data->status) + if (!bad) return; - err = whitespace_error_string(data->status); + data->status |= bad; + err = whitespace_error_string(bad); fprintf(data->file, "%s:%d: %s.\n", data->filename, data->lineno, err); free(err); emit_line(data->file, set, reset, line, 1); @@ -3352,9 +3357,8 @@ int diff_result_code(struct diff_options *opt, int status) void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *base, const char *path) + const char *concatpath) { - char concatpath[PATH_MAX]; struct diff_filespec *one, *two; if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode)) @@ -3376,9 +3380,6 @@ void diff_addremove(struct diff_options *options, addremove = (addremove == '+' ? '-' : addremove == '-' ? '+' : addremove); - if (!path) path = ""; - sprintf(concatpath, "%s%s", base, path); - if (options->prefix && strncmp(concatpath, options->prefix, options->prefix_length)) return; @@ -3399,9 +3400,8 @@ void diff_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *base, const char *path) + const char *concatpath) { - char concatpath[PATH_MAX]; struct diff_filespec *one, *two; if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode) @@ -3414,8 +3414,6 @@ void diff_change(struct diff_options *options, tmp = old_mode; old_mode = new_mode; new_mode = tmp; tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c; } - if (!path) path = ""; - sprintf(concatpath, "%s%s", base, path); if (options->prefix && strncmp(concatpath, options->prefix, options->prefix_length)) @@ -14,12 +14,12 @@ typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *base, const char *path); + const char *fullpath); typedef void (*add_remove_fn_t)(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *base, const char *path); + const char *fullpath); typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, struct diff_options *options, void *data); @@ -164,14 +164,13 @@ extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, const unsigned char *sha1, - const char *base, - const char *path); + const char *fullpath); extern void diff_change(struct diff_options *, unsigned mode1, unsigned mode2, const unsigned char *sha1, const unsigned char *sha2, - const char *base, const char *path); + const char *fullpath); extern void diff_unmerge(struct diff_options *, const char *path, diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 903953e68e..709caa9055 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -394,9 +394,9 @@ sub list_and_choose { if ($choice =~ s/^-//) { $choose = 0; } - # A range can be specified like 5-7 - if ($choice =~ /^(\d+)-(\d+)$/) { - ($bottom, $top) = ($1, $2); + # A range can be specified like 5-7 or 5-. + if ($choice =~ /^(\d+)-(\d*)$/) { + ($bottom, $top) = ($1, length($2) ? $2 : 1 + @stuff); } elsif ($choice =~ /^\d+$/) { $bottom = $top = $choice; @@ -30,7 +30,8 @@ set_reflog_action am require_work_tree cd_to_toplevel -git var GIT_COMMITTER_IDENT >/dev/null || exit +git var GIT_COMMITTER_IDENT >/dev/null || + die "You need to set your committer info first" stop_here () { echo "$1" >"$dotest/next" @@ -421,7 +422,7 @@ do else action=yes fi - FIRSTLINE=$(head -1 "$dotest/final-commit") + FIRSTLINE=$(sed 1q "$dotest/final-commit") if test $action = skip then diff --git a/git-cvsimport.perl b/git-cvsimport.perl index cacbfc0259..7e95fb3740 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -952,7 +952,7 @@ while (<CVS>) { } elsif (/^-+$/) { # end of unknown-line processing $state = 1; } elsif ($state != 11) { # ignore stuff when skipping - print "* UNKNOWN LINE * $_\n"; + print STDERR "* UNKNOWN LINE * $_\n"; } } commit() if $branch and $state != 11; diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 920bbe15a3..b00d1c29cd 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -1884,7 +1884,7 @@ sub req_annotate } # done; get out of the tempdir - cleanupWorkDir(); + cleanupWorkTree(); print "ok\n"; diff --git a/git-merge.sh b/git-merge.sh index 5fc5f5201f..8026ccff4a 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -13,7 +13,7 @@ n don't show a diffstat at the end of the merge summary (synonym to --stat) log add list of one-line log to merge commit message squash create a single commit instead of doing a merge -commit perform a commit if the merge sucesses (default) +commit perform a commit if the merge succeeds (default) ff allow fast forward (default) s,strategy= merge strategy to use m,message= message to be used for the merge commit (if any) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index a64d9d57ab..e3f65bd880 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -162,6 +162,8 @@ pick_one_preserving_merges () { new_parents="$new_parents $new_p" ;; esac + else + new_parents="$new_parents $p" fi done case $fast_forward in diff --git a/git-rebase.sh b/git-rebase.sh index dd7dfe123c..e2d85eeeab 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -150,6 +150,9 @@ while test $# != 0 do case "$1" in --continue) + test -d "$dotest" -o -d .dotest || + die "No rebase in progress?" + git diff-files --quiet --ignore-submodules || { echo "You must edit all merge conflicts and then" echo "mark them as resolved using git add" @@ -178,6 +181,9 @@ do exit ;; --skip) + test -d "$dotest" -o -d .dotest || + die "No rebase in progress?" + git reset --hard HEAD || exit $? if test -d "$dotest" then @@ -203,16 +209,16 @@ do exit ;; --abort) + test -d "$dotest" -o -d .dotest || + die "No rebase in progress?" + git rerere clear if test -d "$dotest" then move_to_original_branch - elif test -d .dotest - then + else dotest=.dotest move_to_original_branch - else - die "No rebase in progress?" fi git reset --hard $(cat "$dotest/orig-head") rm -r "$dotest" diff --git a/git-send-email.perl b/git-send-email.perl index 0b04ba32f0..385ff7c219 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -850,7 +850,7 @@ foreach my $t (@files) { } elsif (/^Content-type:/i) { $has_content_type = 1; - if (/charset="?[^ "]+/) { + if (/charset="?([^ "]+)/) { $body_encoding = $1; } push @xh, $_; diff --git a/git-submodule.sh b/git-submodule.sh index 3eb78cc724..21e5b5b7da 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -167,8 +167,7 @@ cmd_add() # perhaps the path exists and is already a git repo, else clone it if test -e "$path" then - if test -d "$path/.git" && - test "$(unset GIT_DIR; cd $path; git rev-parse --git-dir)" = ".git" + if test -d "$path"/.git -o -f "$path"/.git then echo "Adding existing repo at '$path' to the index" else @@ -270,6 +269,7 @@ cmd_update() do case "$1" in -q|--quiet) + shift quiet=1 ;; -i|--init) @@ -287,7 +287,6 @@ cmd_update() break ;; esac - shift done git ls-files --stage -- "$@" | grep '^160000 ' | diff --git a/git-svn.perl b/git-svn.perl index a54979dc51..a366c891dc 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -643,6 +643,8 @@ sub canonicalize_path { $path =~ s#/[^/]+/\.\.##g; $path =~ s#/$##g; $path =~ s#^\./## if $dot_slash_added; + $path =~ s#^/##; + $path =~ s#^\.$##; return $path; } @@ -1462,13 +1464,6 @@ sub verify_remotes_sanity { } } -# we allow more chars than remotes2config.sh... -sub sanitize_remote_name { - my ($name) = @_; - $name =~ tr{A-Za-z0-9:,/+-}{.}c; - $name; -} - sub find_existing_remote { my ($url, $remotes) = @_; return undef if $no_reuse_existing; @@ -2577,8 +2572,8 @@ sub rebuild { my ($log, $ctx) = command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/, $self->refname, '--'); - my $full_url = $self->full_url; - remove_username($full_url); + my $metadata_url = $self->metadata_url; + remove_username($metadata_url); my $svn_uuid = $self->ra_uuid; my $c; while (<$log>) { @@ -2596,7 +2591,7 @@ sub rebuild { # if we merged or otherwise started elsewhere, this is # how we break out of it if (($uuid ne $svn_uuid) || - ($full_url && $url && ($url ne $full_url))) { + ($metadata_url && $url && ($url ne $metadata_url))) { next; } @@ -2853,7 +2848,7 @@ sub _new { unless (defined $ref_id && length $ref_id) { $_[2] = $ref_id = $Git::SVN::default_ref_id; } - $_[1] = $repo_id = sanitize_remote_name($repo_id); + $_[1] = $repo_id; my $dir = "$ENV{GIT_DIR}/svn/$ref_id"; $_[3] = $path = '' unless (defined $path); mkpath(["$ENV{GIT_DIR}/svn"]); @@ -3243,7 +3238,9 @@ sub close_file { my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1); my $result; while ($result = sysread($fh, my $string, 1024)) { - syswrite($tmp_fh, $string, $result); + my $wrote = syswrite($tmp_fh, $string, $result); + defined($wrote) && $wrote == $result + or croak("write $tmp_filename: $!\n"); } defined $result or croak $!; close $tmp_fh or croak $!; @@ -3251,6 +3248,7 @@ sub close_file { close $fh or croak $!; $hash = $::_repository->hash_and_insert_object($tmp_filename); + unlink($tmp_filename); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; close $fb->{base} or croak $!; } else { @@ -4704,8 +4702,7 @@ sub minimize_connections { # skip existing cases where we already connect to the root if (($ra->{url} eq $ra->{repos_root}) || - (Git::SVN::sanitize_remote_name($ra->{repos_root}) eq - $repo_id)) { + ($ra->{repos_root} eq $repo_id)) { $root_repos->{$ra->{url}} = $repo_id; next; } @@ -4744,8 +4741,7 @@ sub minimize_connections { foreach my $url (keys %$new_urls) { # see if we can re-use an existing [svn-remote "repo_id"] # instead of creating a(n ugly) new section: - my $repo_id = $root_repos->{$url} || - Git::SVN::sanitize_remote_name($url); + my $repo_id = $root_repos->{$url} || $url; my $fetch = $new_urls->{$url}; foreach my $path (keys %$fetch) { diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4de964792f..49b01d8c25 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1500,9 +1500,13 @@ sub git_cmd { return $GIT, '--git-dir='.$git_dir; } -# returns path to the core git executable and the --git-dir parameter as string -sub git_cmd_str { - return join(' ', git_cmd()); +# quote the given arguments for passing them to the shell +# quote_command("command", "arg 1", "arg with ' and ! characters") +# => "'command' 'arg 1' 'arg with '\'' and '\!' characters'" +# Try to avoid using this function wherever possible. +sub quote_command { + return join(' ', + map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ )); } # get HEAD ref of given project as hash @@ -2158,49 +2162,6 @@ sub parse_commits { return wantarray ? @cos : \@cos; } -# parse ref from ref_file, given by ref_id, with given type -sub parse_ref { - my $ref_file = shift; - my $ref_id = shift; - my $type = shift || git_get_type($ref_id); - my %ref_item; - - $ref_item{'type'} = $type; - $ref_item{'id'} = $ref_id; - $ref_item{'epoch'} = 0; - $ref_item{'age'} = "unknown"; - if ($type eq "tag") { - my %tag = parse_tag($ref_id); - $ref_item{'comment'} = $tag{'comment'}; - if ($tag{'type'} eq "commit") { - my %co = parse_commit($tag{'object'}); - $ref_item{'epoch'} = $co{'committer_epoch'}; - $ref_item{'age'} = $co{'age_string'}; - } elsif (defined($tag{'epoch'})) { - my $age = time - $tag{'epoch'}; - $ref_item{'epoch'} = $tag{'epoch'}; - $ref_item{'age'} = age_string($age); - } - $ref_item{'reftype'} = $tag{'type'}; - $ref_item{'name'} = $tag{'name'}; - $ref_item{'refid'} = $tag{'object'}; - } elsif ($type eq "commit"){ - my %co = parse_commit($ref_id); - $ref_item{'reftype'} = "commit"; - $ref_item{'name'} = $ref_file; - $ref_item{'title'} = $co{'title'}; - $ref_item{'refid'} = $ref_id; - $ref_item{'epoch'} = $co{'committer_epoch'}; - $ref_item{'age'} = $co{'age_string'}; - } else { - $ref_item{'reftype'} = $type; - $ref_item{'name'} = $ref_file; - $ref_item{'refid'} = $ref_id; - } - - return %ref_item; -} - # parse line of git-diff-tree "raw" output sub parse_difftree_raw_line { my $line = shift; @@ -4633,7 +4594,6 @@ sub git_snapshot { $hash = git_get_head_hash($project); } - my $git_command = git_cmd_str(); my $name = $project; $name =~ s,([^/])/*\.git$,$1,; $name = basename($name); @@ -4641,11 +4601,12 @@ sub git_snapshot { $name =~ s/\047/\047\\\047\047/g; my $cmd; $filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}"; - $cmd = "$git_command archive " . - "--format=$known_snapshot_formats{$format}{'format'} " . - "--prefix=\'$name\'/ $hash"; + $cmd = quote_command( + git_cmd(), 'archive', + "--format=$known_snapshot_formats{$format}{'format'}", + "--prefix=$name/", $hash); if (exists $known_snapshot_formats{$format}{'compressor'}) { - $cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}}; + $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}}); } print $cgi->header( @@ -4858,8 +4819,8 @@ sub git_object { if ($hash || ($hash_base && !defined $file_name)) { my $object_id = $hash || $hash_base; - my $git_command = git_cmd_str(); - open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null" + open my $fd, "-|", quote_command( + git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null' or die_error('404 Not Found', "Object does not exist"); $type = <$fd>; chomp $type; diff --git a/http-walker.c b/http-walker.c index 99f397e32b..74033060c4 100644 --- a/http-walker.c +++ b/http-walker.c @@ -442,6 +442,8 @@ static int setup_index(struct walker *walker, struct alt_base *repo, unsigned ch return -1; new_pack = parse_pack_index(sha1); + if (!new_pack) + return -1; /* parse_pack_index() already issued error message */ new_pack->next = repo->packs; repo->packs = new_pack; return 0; @@ -13,14 +13,14 @@ static CURL *curl_default; char curl_errorstr[CURL_ERROR_SIZE]; static int curl_ssl_verify = -1; -static char *ssl_cert = NULL; +static const char *ssl_cert = NULL; #if LIBCURL_VERSION_NUM >= 0x070902 -static char *ssl_key = NULL; +static const char *ssl_key = NULL; #endif #if LIBCURL_VERSION_NUM >= 0x070908 -static char *ssl_capath = NULL; +static const char *ssl_capath = NULL; #endif -static char *ssl_cainfo = NULL; +static const char *ssl_cainfo = NULL; static long curl_low_speed_limit = -1; static long curl_low_speed_time = -1; static int curl_ftp_no_epsv = 0; @@ -30,10 +30,11 @@ static struct curl_slist *pragma_header; static struct active_request_slot *active_queue_head = NULL; -size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, - struct buffer *buffer) +size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_) { size_t size = eltsize * nmemb; + struct buffer *buffer = buffer_; + if (size > buffer->buf.len - buffer->posn) size = buffer->buf.len - buffer->posn; memcpy(ptr, buffer->buf.buf + buffer->posn, size); @@ -42,17 +43,17 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, return size; } -size_t fwrite_buffer(const void *ptr, size_t eltsize, - size_t nmemb, struct strbuf *buffer) +size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_) { size_t size = eltsize * nmemb; + struct strbuf *buffer = buffer_; + strbuf_add(buffer, ptr, size); data_received++; return size; } -size_t fwrite_null(const void *ptr, size_t eltsize, - size_t nmemb, struct strbuf *buffer) +size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf) { data_received++; return eltsize * nmemb; @@ -100,39 +101,27 @@ static int http_options(const char *var, const char *value, void *cb) } if (!strcmp("http.sslcert", var)) { - if (ssl_cert == NULL) { - if (!value) - return config_error_nonbool(var); - ssl_cert = xstrdup(value); - } + if (ssl_cert == NULL) + return git_config_string(&ssl_cert, var, value); return 0; } #if LIBCURL_VERSION_NUM >= 0x070902 if (!strcmp("http.sslkey", var)) { - if (ssl_key == NULL) { - if (!value) - return config_error_nonbool(var); - ssl_key = xstrdup(value); - } + if (ssl_key == NULL) + return git_config_string(&ssl_key, var, value); return 0; } #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) { - if (ssl_capath == NULL) { - if (!value) - return config_error_nonbool(var); - ssl_capath = xstrdup(value); - } + if (ssl_capath == NULL) + return git_config_string(&ssl_capath, var, value); return 0; } #endif if (!strcmp("http.sslcainfo", var)) { - if (ssl_cainfo == NULL) { - if (!value) - return config_error_nonbool(var); - ssl_cainfo = xstrdup(value); - } + if (ssl_cainfo == NULL) + return git_config_string(&ssl_cainfo, var, value); return 0; } @@ -64,12 +64,9 @@ struct buffer }; /* Curl request read/write callbacks */ -extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, - struct buffer *buffer); -extern size_t fwrite_buffer(const void *ptr, size_t eltsize, - size_t nmemb, struct strbuf *buffer); -extern size_t fwrite_null(const void *ptr, size_t eltsize, - size_t nmemb, struct strbuf *buffer); +extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf); +extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf); +extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf); /* Slot lifecycle functions */ extern struct active_request_slot *get_active_slot(void); diff --git a/index-pack.c b/index-pack.c index 5ac91baf98..7d5344abc0 100644 --- a/index-pack.c +++ b/index-pack.c @@ -26,6 +26,14 @@ union delta_base { off_t offset; }; +struct base_data { + struct base_data *base; + struct base_data *child; + struct object_entry *obj; + void *data; + unsigned long size; +}; + /* * Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want * to memcmp() only the first 20 bytes. @@ -43,6 +51,8 @@ struct delta_entry static struct object_entry *objects; static struct delta_entry *deltas; +static struct base_data *base_cache; +static size_t base_cache_used; static int nr_objects; static int nr_deltas; static int nr_resolved_deltas; @@ -210,6 +220,46 @@ static void bad_object(unsigned long offset, const char *format, ...) die("pack has bad object at offset %lu: %s", offset, buf); } +static void prune_base_data(struct base_data *retain) +{ + struct base_data *b = base_cache; + for (b = base_cache; + base_cache_used > delta_base_cache_limit && b; + b = b->child) { + if (b->data && b != retain) { + free(b->data); + b->data = NULL; + base_cache_used -= b->size; + } + } +} + +static void link_base_data(struct base_data *base, struct base_data *c) +{ + if (base) + base->child = c; + else + base_cache = c; + + c->base = base; + c->child = NULL; + base_cache_used += c->size; + prune_base_data(c); +} + +static void unlink_base_data(struct base_data *c) +{ + struct base_data *base = c->base; + if (base) + base->child = NULL; + else + base_cache = NULL; + if (c->data) { + free(c->data); + base_cache_used -= c->size; + } +} + static void *unpack_entry_data(unsigned long offset, unsigned long size) { z_stream stream; @@ -425,33 +475,60 @@ static void sha1_object(const void *data, unsigned long size, } } -static void resolve_delta(struct object_entry *delta_obj, void *base_data, - unsigned long base_size, enum object_type type) +static void *get_base_data(struct base_data *c) +{ + if (!c->data) { + struct object_entry *obj = c->obj; + + if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) { + void *base = get_base_data(c->base); + void *raw = get_data_from_pack(obj); + c->data = patch_delta( + base, c->base->size, + raw, obj->size, + &c->size); + free(raw); + if (!c->data) + bad_object(obj->idx.offset, "failed to apply delta"); + } else + c->data = get_data_from_pack(obj); + + base_cache_used += c->size; + prune_base_data(c); + } + return c->data; +} + +static void resolve_delta(struct object_entry *delta_obj, + struct base_data *base_obj, enum object_type type) { void *delta_data; unsigned long delta_size; - void *result; - unsigned long result_size; union delta_base delta_base; int j, first, last; + struct base_data result; delta_obj->real_type = type; delta_data = get_data_from_pack(delta_obj); delta_size = delta_obj->size; - result = patch_delta(base_data, base_size, delta_data, delta_size, - &result_size); + result.data = patch_delta(get_base_data(base_obj), base_obj->size, + delta_data, delta_size, + &result.size); free(delta_data); - if (!result) + if (!result.data) bad_object(delta_obj->idx.offset, "failed to apply delta"); - sha1_object(result, result_size, type, delta_obj->idx.sha1); + sha1_object(result.data, result.size, type, delta_obj->idx.sha1); nr_resolved_deltas++; + result.obj = delta_obj; + link_base_data(base_obj, &result); + hashcpy(delta_base.sha1, delta_obj->idx.sha1); if (!find_delta_children(&delta_base, &first, &last)) { for (j = first; j <= last; j++) { struct object_entry *child = objects + deltas[j].obj_no; if (child->real_type == OBJ_REF_DELTA) - resolve_delta(child, result, result_size, type); + resolve_delta(child, &result, type); } } @@ -461,11 +538,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data, for (j = first; j <= last; j++) { struct object_entry *child = objects + deltas[j].obj_no; if (child->real_type == OBJ_OFS_DELTA) - resolve_delta(child, result, result_size, type); + resolve_delta(child, &result, type); } } - free(result); + unlink_base_data(&result); } static int compare_delta_entry(const void *a, const void *b) @@ -480,7 +557,6 @@ static void parse_pack_objects(unsigned char *sha1) { int i; struct delta_entry *delta = deltas; - void *data; struct stat st; /* @@ -495,7 +571,7 @@ static void parse_pack_objects(unsigned char *sha1) nr_objects); for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; - data = unpack_raw_entry(obj, &delta->base); + void *data = unpack_raw_entry(obj, &delta->base); obj->real_type = obj->type; if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) { nr_deltas++; @@ -544,6 +620,7 @@ static void parse_pack_objects(unsigned char *sha1) struct object_entry *obj = &objects[i]; union delta_base base; int j, ref, ref_first, ref_last, ofs, ofs_first, ofs_last; + struct base_data base_obj; if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) continue; @@ -554,22 +631,24 @@ static void parse_pack_objects(unsigned char *sha1) ofs = !find_delta_children(&base, &ofs_first, &ofs_last); if (!ref && !ofs) continue; - data = get_data_from_pack(obj); + base_obj.data = get_data_from_pack(obj); + base_obj.size = obj->size; + base_obj.obj = obj; + link_base_data(NULL, &base_obj); + if (ref) for (j = ref_first; j <= ref_last; j++) { struct object_entry *child = objects + deltas[j].obj_no; if (child->real_type == OBJ_REF_DELTA) - resolve_delta(child, data, - obj->size, obj->type); + resolve_delta(child, &base_obj, obj->type); } if (ofs) for (j = ofs_first; j <= ofs_last; j++) { struct object_entry *child = objects + deltas[j].obj_no; if (child->real_type == OBJ_OFS_DELTA) - resolve_delta(child, data, - obj->size, obj->type); + resolve_delta(child, &base_obj, obj->type); } - free(data); + unlink_base_data(&base_obj); display_progress(progress, nr_resolved_deltas); } } @@ -600,7 +679,8 @@ static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_c return size; } -static void append_obj_to_pack(const unsigned char *sha1, void *buf, +static struct object_entry *append_obj_to_pack( + const unsigned char *sha1, void *buf, unsigned long size, enum object_type type) { struct object_entry *obj = &objects[nr_objects++]; @@ -618,9 +698,14 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf, write_or_die(output_fd, header, n); obj[0].idx.crc32 = crc32(0, Z_NULL, 0); obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n); + obj[0].size = size; + obj[0].hdr_size = n; + obj[0].type = type; + obj[0].real_type = type; obj[1].idx.offset = obj[0].idx.offset + n; obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32); hashcpy(obj->idx.sha1, sha1); + return obj; } static int delta_pos_compare(const void *_a, const void *_b) @@ -655,28 +740,31 @@ static void fix_unresolved_deltas(int nr_unresolved) for (i = 0; i < n; i++) { struct delta_entry *d = sorted_by_pos[i]; - void *data; - unsigned long size; enum object_type type; int j, first, last; + struct base_data base_obj; if (objects[d->obj_no].real_type != OBJ_REF_DELTA) continue; - data = read_sha1_file(d->base.sha1, &type, &size); - if (!data) + base_obj.data = read_sha1_file(d->base.sha1, &type, &base_obj.size); + if (!base_obj.data) continue; + if (check_sha1_signature(d->base.sha1, base_obj.data, + base_obj.size, typename(type))) + die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); + base_obj.obj = append_obj_to_pack(d->base.sha1, base_obj.data, + base_obj.size, type); + link_base_data(NULL, &base_obj); + find_delta_children(&d->base, &first, &last); for (j = first; j <= last; j++) { struct object_entry *child = objects + deltas[j].obj_no; if (child->real_type == OBJ_REF_DELTA) - resolve_delta(child, data, size, type); + resolve_delta(child, &base_obj, type); } - if (check_sha1_signature(d->base.sha1, data, size, typename(type))) - die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); - append_obj_to_pack(d->base.sha1, data, size, type); - free(data); + unlink_base_data(&base_obj); display_progress(progress, nr_resolved_deltas); } free(sorted_by_pos); diff --git a/parse-options.c b/parse-options.c index acf3fe3a1a..12c882296e 100644 --- a/parse-options.c +++ b/parse-options.c @@ -344,7 +344,10 @@ void usage_with_options_internal(const char * const *usagestr, break; case OPTION_INTEGER: if (opts->flags & PARSE_OPT_OPTARG) - pos += fprintf(stderr, "[<n>]"); + if (opts->long_name) + pos += fprintf(stderr, "[=<n>]"); + else + pos += fprintf(stderr, "[<n>]"); else pos += fprintf(stderr, " <n>"); break; @@ -355,12 +358,18 @@ void usage_with_options_internal(const char * const *usagestr, case OPTION_STRING: if (opts->argh) { if (opts->flags & PARSE_OPT_OPTARG) - pos += fprintf(stderr, " [<%s>]", opts->argh); + if (opts->long_name) + pos += fprintf(stderr, "[=<%s>]", opts->argh); + else + pos += fprintf(stderr, "[<%s>]", opts->argh); else pos += fprintf(stderr, " <%s>", opts->argh); } else { if (opts->flags & PARSE_OPT_OPTARG) - pos += fprintf(stderr, " [...]"); + if (opts->long_name) + pos += fprintf(stderr, "[=...]"); + else + pos += fprintf(stderr, "[...]"); else pos += fprintf(stderr, " ..."); } @@ -416,3 +425,15 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg, *(unsigned long *)(opt->value) = approxidate(arg); return 0; } + +/* + * This should really be OPTION_FILENAME type as a part of + * parse_options that take prefix to do this while parsing. + */ +extern const char *parse_options_fix_filename(const char *prefix, const char *file) +{ + if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file)) + return file; + return prefix_filename(prefix, strlen(prefix), file); +} + diff --git a/parse-options.h b/parse-options.h index 4ee443dafe..13ad15869e 100644 --- a/parse-options.h +++ b/parse-options.h @@ -123,4 +123,6 @@ extern int parse_opt_approxidate_cb(const struct option *, const char *, int); "use <n> digits to display SHA-1s", \ PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 } +extern const char *parse_options_fix_filename(const char *prefix, const char *file); + #endif @@ -272,7 +272,7 @@ int adjust_shared_perm(const char *path) int tweak = shared_repository; if (!(mode & S_IWUSR)) tweak &= ~0222; - mode = (mode & ~0777) | tweak; + mode |= tweak; } else { /* Preserve old PERM_UMASK behaviour */ if (mode & S_IWUSR) @@ -330,6 +330,23 @@ const char *make_nonrelative_path(const char *path) /* We allow "recursive" symbolic links. Only within reason, though. */ #define MAXDEPTH 5 +const char *make_relative_path(const char *abs, const char *base) +{ + static char buf[PATH_MAX + 1]; + int baselen; + if (!base) + return abs; + baselen = strlen(base); + if (prefixcmp(abs, base)) + return abs; + if (abs[baselen] == '/') + baselen++; + else if (base[baselen - 1] != '/') + return abs; + strcpy(buf, abs + baselen); + return buf; +} + const char *make_absolute_path(const char *path) { static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; @@ -3,6 +3,8 @@ #include "utf8.h" #include "diff.h" #include "revision.h" +#include "path-list.h" +#include "mailmap.h" static char *user_format; @@ -288,6 +290,25 @@ static char *logmsg_reencode(const struct commit *commit, return out; } +static int mailmap_name(struct strbuf *sb, const char *email) +{ + static struct path_list *mail_map; + char buffer[1024]; + + if (!mail_map) { + mail_map = xcalloc(1, sizeof(*mail_map)); + read_mailmap(mail_map, ".mailmap", NULL); + } + + if (!mail_map->nr) + return -1; + + if (!map_email(mail_map, email, buffer, sizeof(buffer))) + return -1; + strbuf_addstr(sb, buffer); + return 0; +} + static size_t format_person_part(struct strbuf *sb, char part, const char *msg, int len) { @@ -309,10 +330,12 @@ static size_t format_person_part(struct strbuf *sb, char part, if (end >= len - 2) goto skip; - if (part == 'n') { /* name */ + if (part == 'n' || part == 'N') { /* name */ while (end > 0 && isspace(msg[end - 1])) end--; - strbuf_add(sb, msg, end); + if (part != 'N' || !msg[end] || !msg[end + 1] || + mailmap_name(sb, msg + end + 2) < 0) + strbuf_add(sb, msg, end); return placeholder_len; } start = ++end; /* save email start position */ diff --git a/read-cache.c b/read-cache.c index 8e5fbb6192..f83de8c415 100644 --- a/read-cache.c +++ b/read-cache.c @@ -138,6 +138,16 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } +static int is_empty_blob_sha1(const unsigned char *sha1) +{ + static const unsigned char empty_blob_sha1[20] = { + 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b, + 0x29,0xae,0x77,0x5a,0xd8,0xc2,0xe4,0x8c,0x53,0x91 + }; + + return !hashcmp(sha1, empty_blob_sha1); +} + static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) { unsigned int changed = 0; @@ -193,6 +203,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) if (ce->ce_size != (unsigned int) st->st_size) changed |= DATA_CHANGED; + /* Racily smudged entry? */ + if (!ce->ce_size) { + if (!is_empty_blob_sha1(ce->sha1)) + changed |= DATA_CHANGED; + } + return changed; } @@ -925,7 +925,7 @@ int delete_ref(const char *refname, const unsigned char *sha1) i = strlen(lock->lk->filename) - 5; /* .lock */ lock->lk->filename[i] = 0; err = unlink(lock->lk->filename); - if (err) { + if (err && errno != ENOENT) { ret = 1; error("unlink(%s) failed: %s", lock->lk->filename, strerror(errno)); @@ -424,6 +424,28 @@ static void read_config(void) alias_all_urls(); } +/* + * We need to make sure the tracking branches are well formed, but a + * wildcard refspec in "struct refspec" must have a trailing slash. We + * temporarily drop the trailing '/' while calling check_ref_format(), + * and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL + * error return is Ok for a wildcard refspec. + */ +static int verify_refname(char *name, int is_glob) +{ + int result, len = -1; + + if (is_glob) { + len = strlen(name); + assert(name[len - 1] == '/'); + name[len - 1] = '\0'; + } + result = check_ref_format(name); + if (is_glob) + name[len - 1] = '/'; + return result; +} + static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; @@ -431,11 +453,11 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); for (i = 0; i < nr_refspec; i++) { - size_t llen, rlen; + size_t llen; int is_glob; const char *lhs, *rhs; - llen = rlen = is_glob = 0; + llen = is_glob = 0; lhs = refspec[i]; if (*lhs == '+') { @@ -455,12 +477,9 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp } if (rhs) { - rhs++; - rlen = strlen(rhs); + size_t rlen = strlen(++rhs); is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); - if (is_glob) - rlen -= 2; - rs[i].dst = xstrndup(rhs, rlen); + rs[i].dst = xstrndup(rhs, rlen - is_glob); } llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); @@ -468,7 +487,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if ((rhs && !is_glob) || (!rhs && fetch)) goto invalid; is_glob = 1; - llen -= 2; + llen--; } else if (rhs && is_glob) { goto invalid; } @@ -485,7 +504,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (!*rs[i].src) ; /* empty is ok */ else { - st = check_ref_format(rs[i].src); + st = verify_refname(rs[i].src, is_glob); if (st && st != CHECK_REF_FORMAT_ONELEVEL) goto invalid; } @@ -500,7 +519,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp } else if (!*rs[i].dst) { ; /* ok */ } else { - st = check_ref_format(rs[i].dst); + st = verify_refname(rs[i].dst, is_glob); if (st && st != CHECK_REF_FORMAT_ONELEVEL) goto invalid; } @@ -515,7 +534,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (!*rs[i].src) ; /* empty is ok */ else if (is_glob) { - st = check_ref_format(rs[i].src); + st = verify_refname(rs[i].src, is_glob); if (st && st != CHECK_REF_FORMAT_ONELEVEL) goto invalid; } @@ -529,13 +548,13 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp * - otherwise it must be a valid looking ref. */ if (!rs[i].dst) { - st = check_ref_format(rs[i].src); + st = verify_refname(rs[i].src, is_glob); if (st && st != CHECK_REF_FORMAT_ONELEVEL) goto invalid; } else if (!*rs[i].dst) { goto invalid; } else { - st = check_ref_format(rs[i].dst); + st = verify_refname(rs[i].dst, is_glob); if (st && st != CHECK_REF_FORMAT_ONELEVEL) goto invalid; } @@ -684,8 +703,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (!prefixcmp(needle, key) && - needle[strlen(key)] == '/') { + if (!prefixcmp(needle, key)) { *result = xmalloc(strlen(value) + strlen(needle) - strlen(key) + 1); @@ -867,8 +885,7 @@ static char *guess_ref(const char *name, struct ref *peer) static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, - struct refspec *rs, - int errs) + struct refspec *rs) { struct ref *matched_src, *matched_dst; @@ -876,7 +893,7 @@ static int match_explicit(struct ref *src, struct ref *dst, char *dst_guess; if (rs->pattern || rs->matching) - return errs; + return 0; matched_src = matched_dst = NULL; switch (count_refspec_match(rs->src, src, &matched_src)) { @@ -889,23 +906,16 @@ static int match_explicit(struct ref *src, struct ref *dst, */ matched_src = try_explicit_object_name(rs->src); if (!matched_src) - error("src refspec %s does not match any.", rs->src); + return error("src refspec %s does not match any.", rs->src); break; default: - matched_src = NULL; - error("src refspec %s matches more than one.", rs->src); - break; + return error("src refspec %s matches more than one.", rs->src); } - if (!matched_src) - errs = 1; - if (!dst_value) { unsigned char sha1[20]; int flag; - if (!matched_src) - return errs; dst_value = resolve_ref(matched_src->name, sha1, 1, &flag); if (!dst_value || ((flag & REF_ISSYMREF) && @@ -936,18 +946,16 @@ static int match_explicit(struct ref *src, struct ref *dst, dst_value); break; } - if (errs || !matched_dst) - return 1; - if (matched_dst->peer_ref) { - errs = 1; - error("dst ref %s receives from more than one src.", + if (!matched_dst) + return -1; + if (matched_dst->peer_ref) + return error("dst ref %s receives from more than one src.", matched_dst->name); - } else { matched_dst->peer_ref = matched_src; matched_dst->force = rs->force; } - return errs; + return 0; } static int match_explicit_refs(struct ref *src, struct ref *dst, @@ -956,8 +964,8 @@ static int match_explicit_refs(struct ref *src, struct ref *dst, { int i, errs; for (i = errs = 0; i < rs_nr; i++) - errs |= match_explicit(src, dst, dst_tail, &rs[i], errs); - return -errs; + errs += match_explicit(src, dst, dst_tail, &rs[i]); + return errs; } static const struct refspec *check_pattern_match(const struct refspec *rs, @@ -973,9 +981,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && - !prefixcmp(src->name, rs[i].src) && - src->name[strlen(rs[i].src)] == '/') + if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) return rs + i; } if (matching_refs != -1) diff --git a/revision.c b/revision.c index fc66755259..a68abec3f2 100644 --- a/revision.c +++ b/revision.c @@ -259,7 +259,7 @@ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *base, const char *path) + const char *fullpath) { int diff = REV_TREE_DIFFERENT; @@ -285,7 +285,7 @@ static void file_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *base, const char *path) + const char *fullpath) { tree_difference = REV_TREE_DIFFERENT; DIFF_OPT_SET(options, HAS_CHANGES); @@ -412,10 +412,26 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) commit->object.flags |= TREESAME; } -static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list) +static void insert_by_date_cached(struct commit *p, struct commit_list **head, + struct commit_list *cached_base, struct commit_list **cache) +{ + struct commit_list *new_entry; + + if (cached_base && p->date < cached_base->item->date) + new_entry = insert_by_date(p, &cached_base->next); + else + new_entry = insert_by_date(p, head); + + if (cache && (!*cache || p->date < (*cache)->item->date)) + *cache = new_entry; +} + +static int add_parents_to_list(struct rev_info *revs, struct commit *commit, + struct commit_list **list, struct commit_list **cache_ptr) { struct commit_list *parent = commit->parents; unsigned left_flag; + struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL; if (commit->object.flags & ADDED) return 0; @@ -445,7 +461,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str if (p->object.flags & SEEN) continue; p->object.flags |= SEEN; - insert_by_date(p, list); + insert_by_date_cached(p, list, cached_base, cache_ptr); } return 0; } @@ -470,7 +486,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str p->object.flags |= left_flag; if (!(p->object.flags & SEEN)) { p->object.flags |= SEEN; - insert_by_date(p, list); + insert_by_date_cached(p, list, cached_base, cache_ptr); } if(revs->first_parent_only) break; @@ -611,7 +627,7 @@ static int limit_list(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; - if (add_parents_to_list(revs, commit, &list) < 0) + if (add_parents_to_list(revs, commit, &list, NULL) < 0) return -1; if (obj->flags & UNINTERESTING) { mark_parents_uninteresting(commit); @@ -1458,10 +1474,12 @@ enum rewrite_result { static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp) { + struct commit_list *cache = NULL; + for (;;) { struct commit *p = *pp; if (!revs->limited) - if (add_parents_to_list(revs, p, &revs->commits) < 0) + if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0) return rewrite_one_error; if (p->parents && p->parents->next) return rewrite_one_ok; @@ -1580,7 +1598,7 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) continue; - if (add_parents_to_list(revs, commit, &revs->commits) < 0) + if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) return NULL; } diff --git a/revision.h b/revision.h index abce5001f1..31f08c4056 100644 --- a/revision.h +++ b/revision.h @@ -10,7 +10,6 @@ #define CHILD_SHOWN (1u<<6) #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) -#define TOPOSORT (1u<<9) /* In the active toposort list.. */ struct rev_info; struct log_info; diff --git a/run-command.c b/run-command.c index 44100a749b..7068ec7e6d 100644 --- a/run-command.c +++ b/run-command.c @@ -65,6 +65,8 @@ int start_command(struct child_process *cmd) cmd->err = fderr[0]; } + trace_argv_printf(cmd->argv, "trace: run_command:"); + cmd->pid = fork(); if (cmd->pid < 0) { if (need_in) @@ -292,9 +292,10 @@ void setup_work_tree(void) work_tree = get_git_work_tree(); git_dir = get_git_dir(); if (!is_absolute_path(git_dir)) - set_git_dir(make_absolute_path(git_dir)); + git_dir = make_absolute_path(git_dir); if (!work_tree || chdir(work_tree)) die("This operation must be run in a work tree"); + set_git_dir(make_relative_path(git_dir, work_tree)); initialized = 1; } diff --git a/sha1_file.c b/sha1_file.c index 37bcc5474e..10346b681e 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -116,7 +116,16 @@ int safe_create_leading_directories(char *path) return 0; } -char * sha1_to_hex(const unsigned char *sha1) +int safe_create_leading_directories_const(const char *path) +{ + /* path points to cache entries, so xstrdup before messing with it */ + char *buf = xstrdup(path); + int result = safe_create_leading_directories(buf); + free(buf); + return result; +} + +char *sha1_to_hex(const unsigned char *sha1) { static int bufno; static char hexbuffer[4][50]; @@ -831,13 +840,7 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local) struct packed_git *parse_pack_index(unsigned char *sha1) { - char *path = sha1_pack_index_name(sha1); - return parse_pack_index_file(sha1, path); -} - -struct packed_git *parse_pack_index_file(const unsigned char *sha1, - const char *idx_path) -{ + const char *idx_path = sha1_pack_index_name(sha1); const char *path = sha1_pack_name(sha1); struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2); @@ -1606,6 +1609,7 @@ static void *unpack_delta_entry(struct packed_git *p, off_t base_offset; base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset); + unuse_pack(w_curs); base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0); if (!base) die("failed to read delta base object" @@ -2124,8 +2128,9 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename) fd = mkstemp(buffer); if (fd < 0 && dirlen) { /* Make sure the directory exists */ + memcpy(buffer, filename, dirlen); buffer[dirlen-1] = 0; - if (mkdir(buffer, 0777) && adjust_shared_perm(buffer)) + if (mkdir(buffer, 0777) || adjust_shared_perm(buffer)) return -1; /* Try again */ @@ -2145,20 +2150,6 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen, static char tmpfile[PATH_MAX]; filename = sha1_file_name(sha1); - fd = open(filename, O_RDONLY); - if (fd >= 0) { - /* - * FIXME!!! We might do collision checking here, but we'd - * need to uncompress the old file and check it. Later. - */ - close(fd); - return 0; - } - - if (errno != ENOENT) { - return error("sha1 file %s: %s\n", filename, strerror(errno)); - } - fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename); if (fd < 0) { if (errno == EPERM) @@ -7,6 +7,7 @@ static int do_generic_cmd(const char *me, char *arg) { const char *my_argv[4]; + setup_path(NULL); if (!arg || !(arg = sq_dequote(arg))) die("bad argument"); if (prefixcmp(me, "git-")) @@ -29,7 +30,6 @@ static int do_cvs_cmd(const char *me, char *arg) die("git-cvsserver only handles server: %s", arg); setup_path(NULL); - return execv_git_cmd(cvsserver_argv); } @@ -49,15 +49,24 @@ int main(int argc, char **argv) char *prog; struct commands *cmd; + /* + * Special hack to pretend to be a CVS server + */ if (argc == 2 && !strcmp(argv[1], "cvs server")) argv--; - /* We want to see "-c cmd args", and nothing else */ + + /* + * We do not accept anything but "-c" followed by "cmd arg", + * where "cmd" is a very limited subset of git commands. + */ else if (argc != 3 || strcmp(argv[1], "-c")) die("What do you think I am? A shell?"); prog = argv[2]; - argv += 2; - argc -= 2; + if (!strncmp(prog, "git", 3) && isspace(prog[3])) + /* Accept "git foo" as if the caller said "git-foo". */ + prog[3] = '-'; + for (cmd = cmd_list ; cmd->name ; cmd++) { int len = strlen(cmd->name); char *arg; diff --git a/t/t0001-init.sh b/t/t0001-init.sh index d31887f9bf..c0b781ae49 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -141,4 +141,30 @@ test_expect_success 'reinit' ' test_cmp again/empty again/err2 ' +test_expect_success 'init with --template' ' + mkdir template-source && + echo content >template-source/file && + ( + mkdir template-custom && + cd template-custom && + git init --template=../template-source + ) && + test_cmp template-source/file template-custom/.git/file +' + +test_expect_success 'init with --template (blank)' ' + ( + mkdir template-plain && + cd template-plain && + git init + ) && + test -f template-plain/.git/info/exclude && + ( + mkdir template-blank && + cd template-blank && + git init --template= + ) && + ! test -f template-blank/.git/info/exclude +' + test_done diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh index 9255c63c08..63e1217e71 100755 --- a/t/t0004-unwritable.sh +++ b/t/t0004-unwritable.sh @@ -8,6 +8,7 @@ test_expect_success setup ' >file && git add file && + test_tick && git commit -m initial && echo >file && git add file @@ -17,11 +18,11 @@ test_expect_success setup ' test_expect_success 'write-tree should notice unwritable repository' ' ( - chmod a-w .git/objects + chmod a-w .git/objects .git/objects/?? && test_must_fail git write-tree ) status=$? - chmod 775 .git/objects + chmod 775 .git/objects .git/objects/?? (exit $status) ' @@ -29,11 +30,11 @@ test_expect_success 'write-tree should notice unwritable repository' ' test_expect_success 'commit should notice unwritable repository' ' ( - chmod a-w .git/objects + chmod a-w .git/objects .git/objects/?? && test_must_fail git commit -m second ) status=$? - chmod 775 .git/objects + chmod 775 .git/objects .git/objects/?? (exit $status) ' @@ -41,12 +42,12 @@ test_expect_success 'commit should notice unwritable repository' ' test_expect_success 'update-index should notice unwritable repository' ' ( - echo a >file && - chmod a-w .git/objects + echo 6O >file && + chmod a-w .git/objects .git/objects/?? && test_must_fail git update-index file ) status=$? - chmod 775 .git/objects + chmod 775 .git/objects .git/objects/?? (exit $status) ' @@ -55,11 +56,11 @@ test_expect_success 'add should notice unwritable repository' ' ( echo b >file && - chmod a-w .git/objects + chmod a-w .git/objects .git/objects/?? && test_must_fail git add file ) status=$? - chmod 775 .git/objects + chmod 775 .git/objects .git/objects/?? (exit $status) ' diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 9965cfa1dc..6309aed451 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -11,23 +11,35 @@ cat > expect.err << EOF usage: test-parse-options <options> -b, --boolean get a boolean + -4, --or4 bitwise-or boolean with ...0100 + -i, --integer <n> get a integer -j <n> get a integer, too + --set23 set integer to 23 + -t <time> get timestamp of <time> + -L, --length <str> get length of <str> -string options +String options -s, --string <string> get a string --string2 <str> get another string --st <st> get another string (pervert ordering) -o <str> get another string + --default-string set string to default -magic arguments +Magic arguments --quux means --quux +Standard options + --abbrev[=<n>] use <n> digits to display SHA-1s + -v, --verbose be verbose + -n, --dry-run dry run + -q, --quiet be quiet + EOF test_expect_success 'test help' ' - ! test-parse-options -h > output 2> output.err && + test_must_fail test-parse-options -h > output 2> output.err && test ! -s output && test_cmp expect.err output.err ' @@ -36,21 +48,31 @@ cat > expect << EOF boolean: 2 integer: 1729 string: 123 +abbrev: 7 +verbose: 2 +quiet: no +dry run: yes EOF test_expect_success 'short options' ' - test-parse-options -s123 -b -i 1729 -b > output 2> output.err && + test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err && test_cmp expect output && test ! -s output.err ' + cat > expect << EOF boolean: 2 integer: 1729 string: 321 +abbrev: 10 +verbose: 2 +quiet: no +dry run: no EOF test_expect_success 'long options' ' test-parse-options --boolean --integer 1729 --boolean --string2=321 \ + --verbose --verbose --no-dry-run --abbrev=10 \ > output 2> output.err && test ! -s output.err && test_cmp expect output @@ -60,6 +82,10 @@ cat > expect << EOF boolean: 1 integer: 13 string: 123 +abbrev: 7 +verbose: 0 +quiet: no +dry run: no arg 00: a1 arg 01: b1 arg 02: --boolean @@ -76,6 +102,10 @@ cat > expect << EOF boolean: 0 integer: 2 string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no EOF test_expect_success 'unambiguously abbreviated option' ' @@ -99,6 +129,10 @@ cat > expect << EOF boolean: 0 integer: 0 string: 123 +abbrev: 7 +verbose: 0 +quiet: no +dry run: no EOF test_expect_success 'non ambiguous option (after two options it abbreviates)' ' @@ -107,20 +141,24 @@ test_expect_success 'non ambiguous option (after two options it abbreviates)' ' test_cmp expect output ' -cat > expect.err << EOF +cat > typo.err << EOF error: did you mean \`--boolean\` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - ! test-parse-options -boolean > output 2> output.err && + test_must_fail test-parse-options -boolean > output 2> output.err && test ! -s output && - test_cmp expect.err output.err + test_cmp typo.err output.err ' cat > expect <<EOF boolean: 0 integer: 0 string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no arg 00: --quux EOF @@ -130,4 +168,68 @@ test_expect_success 'keep some options as arguments' ' test_cmp expect output ' +cat > expect <<EOF +boolean: 0 +integer: 1 +string: default +abbrev: 7 +verbose: 0 +quiet: yes +dry run: no +arg 00: foo +EOF + +test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' ' + test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \ + foo -q > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + +cat > expect <<EOF +Callback: "four", 0 +boolean: 5 +integer: 4 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +EOF + +test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' ' + test-parse-options --length=four -b -4 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + +cat > expect <<EOF +Callback: "not set", 1 +EOF + +test_expect_success 'OPT_CALLBACK() and callback errors work' ' + test_must_fail test-parse-options --no-length > output 2> output.err && + test_cmp expect output && + test_cmp expect.err output.err +' + +cat > expect <<EOF +boolean: 1 +integer: 23 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +EOF + +test_expect_success 'OPT_BIT() and OPT_SET_INT() work' ' + test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + +# --or4 +# --no-or4 + test_done diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 6c78c8bc9b..dc85e8b60a 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -17,6 +17,29 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' ' test $ret != "0" ' +for u in 002 022 +do + test_expect_success "shared=1 does not clear bits preset by umask $u" ' + mkdir sub && ( + cd sub && + umask $u && + git init --shared=1 && + test 1 = "$(git config core.sharedrepository)" + ) && + actual=$(ls -l sub/.git/HEAD) + case "$actual" in + -rw-rw-r--*) + : happy + ;; + *) + echo Oops, .git/HEAD is not 0664 but $actual + false + ;; + esac + ' + rm -rf sub +done + test_expect_success 'shared=all' ' mkdir sub && cd sub && diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index d24a47d114..3508d0a612 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -13,7 +13,7 @@ usage: some-command [options] <args>... --bar ... some cool option --bar with an argument An option group Header - -C [...] option C with an optional argument + -C[...] option C with an optional argument Extras --extra1 line above used to cause a segfault but no longer does diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh new file mode 100755 index 0000000000..332694e7d3 --- /dev/null +++ b/t/t2103-update-index-ignore-missing.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +test_description='update-index with options' + +. ./test-lib.sh + +test_expect_success basics ' + >one && + >two && + >three && + + # need --add when adding + test_must_fail git update-index one && + test -z "$(git ls-files)" && + git update-index --add one && + test zone = "z$(git ls-files)" && + + # update-index is atomic + echo 1 >one && + test_must_fail git update-index one two && + echo "M one" >expect && + git diff-files --name-status >actual && + test_cmp expect actual && + + git update-index --add one two three && + for i in one three two; do echo $i; done >expect && + git ls-files >actual && + test_cmp expect actual && + + test_tick && + ( + test_create_repo xyzzy && + cd xyzzy && + >file && + git add file + git commit -m "sub initial" + ) && + git add xyzzy && + + test_tick && + git commit -m initial && + git tag initial +' + +test_expect_success '--ignore-missing --refresh' ' + git reset --hard initial && + echo 2 >one && + test_must_fail git update-index --refresh && + echo 1 >one && + git update-index --refresh && + rm -f two && + test_must_fail git update-index --refresh && + git update-index --ignore-missing --refresh + +' + +test_expect_success '--unmerged --refresh' ' + git reset --hard initial && + info=$(git ls-files -s one | sed -e "s/ 0 / 1 /") && + git rm --cached one && + echo "$info" | git update-index --index-info && + test_must_fail git update-index --refresh && + git update-index --unmerged --refresh && + echo 2 >two && + test_must_fail git update-index --unmerged --refresh >actual && + grep two actual && + ! grep one actual && + ! grep three actual +' + +test_expect_success '--ignore-submodules --refresh (1)' ' + git reset --hard initial && + rm -f two && + test_must_fail git update-index --ignore-submodules --refresh +' + +test_expect_success '--ignore-submodules --refresh (2)' ' + git reset --hard initial && + test_tick && + ( + cd xyzzy && + git commit -m "sub second" --allow-empty + ) && + test_must_fail git update-index --refresh && + test_must_fail git update-index --ignore-missing --refresh && + git update-index --ignore-submodules --refresh +' + +test_done diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh new file mode 100755 index 0000000000..7fe4a6ecb0 --- /dev/null +++ b/t/t3202-show-branch-octopus.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +test_description='test show-branch with more than 8 heads' + +. ./test-lib.sh + +numbers="1 2 3 4 5 6 7 8 9 10" + +test_expect_success 'setup' ' + + > file && + git add file && + test_tick && + git commit -m initial && + + for i in $numbers + do + git checkout -b branch$i master && + > file$i && + git add file$i && + test_tick && + git commit -m branch$i || break + done + +' + +cat > expect << EOF +! [branch1] branch1 + ! [branch2] branch2 + ! [branch3] branch3 + ! [branch4] branch4 + ! [branch5] branch5 + ! [branch6] branch6 + ! [branch7] branch7 + ! [branch8] branch8 + ! [branch9] branch9 + * [branch10] branch10 +---------- + * [branch10] branch10 + + [branch9] branch9 + + [branch8] branch8 + + [branch7] branch7 + + [branch6] branch6 + + [branch5] branch5 + + [branch4] branch4 + + [branch3] branch3 + + [branch2] branch2 ++ [branch1] branch1 ++++++++++* [branch10^] initial +EOF + +test_expect_success 'show-branch with more than 8 branches' ' + + git show-branch $(for i in $numbers; do echo branch$i; done) > out && + test_cmp expect out + +' + +test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index f542f0af41..7893d8c40e 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -217,4 +217,16 @@ test_expect_success 'Remove nonexistent file returns nonzero exit status' ' ! git rm nonexistent ' +test_expect_success 'Call "rm" from outside the work tree' ' + mkdir repo && + cd repo && + git init && + echo something > somefile && + git add somefile && + git commit -m "add a file" && + (cd .. && + git --git-dir=repo/.git --work-tree=repo rm somefile) && + test_must_fail git ls-files --error-unmatch somefile +' + test_done diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh index dc0b7126cc..0d0fb87f57 100755 --- a/t/t4017-diff-retval.sh +++ b/t/t4017-diff-retval.sh @@ -105,4 +105,12 @@ test_expect_success '--check with --no-pager returns 2 for dirty difference' ' ' + +test_expect_success 'check should test not just the last line' ' + echo "" >>a && + git --no-pager diff --check + test $? = 2 + +' + test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index b53645417b..4c8af45f83 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -71,4 +71,5 @@ test_expect_success 'diff-filter=D' ' -test_done
\ No newline at end of file +test_done + diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 9b0baac8db..87902f81ef 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -25,7 +25,6 @@ commit id embedding: ' . ./test-lib.sh -TAR=${TAR:-tar} UNZIP=${UNZIP:-unzip} SUBSTFORMAT=%H%n @@ -68,7 +67,7 @@ test_expect_success \ test_expect_success \ 'validate file modification time' \ 'mkdir extract && - $TAR xf b.tar -C extract a/a && + "$TAR" xf b.tar -C extract a/a && perl -e '\''print((stat("extract/a/a"))[9], "\n")'\'' >b.mtime && echo "1117231200" >expected.mtime && diff expected.mtime b.mtime' @@ -80,7 +79,7 @@ test_expect_success \ test_expect_success \ 'extract tar archive' \ - '(cd b && $TAR xf -) <b.tar' + '(cd b && "$TAR" xf -) <b.tar' test_expect_success \ 'validate filenames' \ @@ -97,7 +96,7 @@ test_expect_success \ test_expect_success \ 'extract tar archive with prefix' \ - '(cd c && $TAR xf -) <c.tar' + '(cd c && "$TAR" xf -) <c.tar' test_expect_success \ 'validate filenames with prefix' \ @@ -117,7 +116,7 @@ test_expect_success \ test_expect_success \ 'extract substfiles' \ - '(mkdir f && cd f && $TAR xf -) <f.tar' + '(mkdir f && cd f && "$TAR" xf -) <f.tar' test_expect_success \ 'validate substfile contents' \ @@ -129,7 +128,7 @@ test_expect_success \ test_expect_success \ 'extract substfiles from archive with prefix' \ - '(mkdir g && cd g && $TAR xf -) <g.tar' + '(mkdir g && cd g && "$TAR" xf -) <g.tar' test_expect_success \ 'validate substfile contents from archive with prefix' \ diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 577ecc210a..e9f3e72c7e 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -11,7 +11,7 @@ test_expect_success 'split sample box' \ 'git mailsplit -o. ../t5100/sample.mbox >last && last=`cat last` && echo total is $last && - test `cat last` = 9' + test `cat last` = 10' for mail in `echo 00*` do diff --git a/t/t5100/0010 b/t/t5100/0010 new file mode 100644 index 0000000000..f5892c9da7 --- /dev/null +++ b/t/t5100/0010 @@ -0,0 +1,35 @@ +From b9704a518e21158433baa2cc2d591fea687967f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lukas=20Sandstr=C3=B6m?= <lukass@etek.chalmers.se> +Date: Thu, 10 Jul 2008 23:41:33 +0200 +Subject: Re: discussion that lead to this patch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[PATCH] git-mailinfo: Fix getting the subject from the body + +"Subject: " isn't in the static array "header", and thus +memcmp("Subject: ", header[i], 7) will never match. + +Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se> +Signed-off-by: Junio C Hamano <gitster@pobox.com> +--- + builtin-mailinfo.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c +index 962aa34..2d1520f 100644 +--- a/builtin-mailinfo.c ++++ b/builtin-mailinfo.c +@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over + return 1; + if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) { + for (i = 0; header[i]; i++) { +- if (!memcmp("Subject: ", header[i], 9)) { ++ if (!memcmp("Subject", header[i], 7)) { + if (! handle_header(line, hdr_data[i], 0)) { + return 1; + } +-- +1.5.6.2.455.g1efb2 + diff --git a/t/t5100/info0010 b/t/t5100/info0010 new file mode 100644 index 0000000000..1791241e46 --- /dev/null +++ b/t/t5100/info0010 @@ -0,0 +1,5 @@ +Author: Lukas Sandström +Email: lukass@etek.chalmers.se +Subject: git-mailinfo: Fix getting the subject from the body +Date: Thu, 10 Jul 2008 23:41:33 +0200 + diff --git a/t/t5100/msg0010 b/t/t5100/msg0010 new file mode 100644 index 0000000000..a96c230092 --- /dev/null +++ b/t/t5100/msg0010 @@ -0,0 +1,5 @@ +"Subject: " isn't in the static array "header", and thus +memcmp("Subject: ", header[i], 7) will never match. + +Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se> +Signed-off-by: Junio C Hamano <gitster@pobox.com> diff --git a/t/t5100/patch0010 b/t/t5100/patch0010 new file mode 100644 index 0000000000..f055481d56 --- /dev/null +++ b/t/t5100/patch0010 @@ -0,0 +1,20 @@ +--- + builtin-mailinfo.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c +index 962aa34..2d1520f 100644 +--- a/builtin-mailinfo.c ++++ b/builtin-mailinfo.c +@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over + return 1; + if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) { + for (i = 0; header[i]; i++) { +- if (!memcmp("Subject: ", header[i], 9)) { ++ if (!memcmp("Subject", header[i], 7)) { + if (! handle_header(line, hdr_data[i], 0)) { + return 1; + } +-- +1.5.6.2.455.g1efb2 + diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index 0476b96c33..aba57f922b 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -430,3 +430,38 @@ index b426a14..97756ec 100644 =20 =20 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the +From b9704a518e21158433baa2cc2d591fea687967f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lukas=20Sandstr=C3=B6m?= <lukass@etek.chalmers.se> +Date: Thu, 10 Jul 2008 23:41:33 +0200 +Subject: Re: discussion that lead to this patch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[PATCH] git-mailinfo: Fix getting the subject from the body + +"Subject: " isn't in the static array "header", and thus +memcmp("Subject: ", header[i], 7) will never match. + +Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se> +Signed-off-by: Junio C Hamano <gitster@pobox.com> +--- + builtin-mailinfo.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c +index 962aa34..2d1520f 100644 +--- a/builtin-mailinfo.c ++++ b/builtin-mailinfo.c +@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over + return 1; + if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) { + for (i = 0; header[i]; i++) { +- if (!memcmp("Subject: ", header[i], 9)) { ++ if (!memcmp("Subject", header[i], 7)) { + if (! handle_header(line, hdr_data[i], 0)) { + return 1; + } +-- +1.5.6.2.455.g1efb2 + diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 9fd9d07000..9fd9d07000 100644..100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh index 1493a92c06..64fe2615ac 100755 --- a/t/t5404-tracking-branches.sh +++ b/t/t5404-tracking-branches.sh @@ -10,6 +10,7 @@ test_expect_success 'setup' ' git commit -m 1 && git branch b1 && git branch b2 && + git branch b3 && git clone . aa && git checkout b1 && echo b1 >>file && @@ -50,4 +51,10 @@ test_expect_success 'deleted branches have their tracking branches removed' ' test "$(git rev-parse origin/b1)" = "origin/b1" ' +test_expect_success 'already deleted tracking branches ignored' ' + git branch -d -r origin/b3 && + git push origin :b3 >output 2>&1 && + ! grep error output +' + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 6946557c67..df7750f7d1 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -37,7 +37,8 @@ test_expect_success "clone and setup child repos" ' echo "Pull: refs/heads/one:refs/heads/one" } >.git/remotes/two && cd .. && - git clone . bundle + git clone . bundle && + git clone . seven ' test_expect_success "fetch test" ' @@ -295,4 +296,11 @@ test_expect_success 'configured fetch updates tracking' ' ) ' +test_expect_success 'pushing nonexistent branch by mistake should not segv' ' + + cd "$D" && + test_must_fail git push seven no:no + +' + test_done diff --git a/t/t5513-fetch-track.sh b/t/t5513-fetch-track.sh new file mode 100755 index 0000000000..9e7486274b --- /dev/null +++ b/t/t5513-fetch-track.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +test_description='fetch follows remote tracking branches correctly' + +. ./test-lib.sh + +test_expect_success setup ' + >file && + git add . && + test_tick && + git commit -m Initial && + git branch b-0 && + git branch b1 && + git branch b/one && + test_create_repo other && + ( + cd other && + git config remote.origin.url .. && + git config remote.origin.fetch "+refs/heads/b/*:refs/remotes/b/*" + ) +' + +test_expect_success fetch ' + ( + cd other && git fetch origin && + test "$(git for-each-ref --format="%(refname)")" = refs/remotes/b/one + ) +' + +test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 593d1a3877..d785b3df78 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -17,17 +17,57 @@ test_expect_success setup ' ' -test_expect_success 'clone with excess parameters' ' +test_expect_success 'clone with excess parameters (1)' ' + rm -fr dst && + test_must_fail git clone -n src dst junk + +' + +test_expect_success 'clone with excess parameters (2)' ' + + rm -fr dst && test_must_fail git clone -n "file://$(pwd)/src" dst junk ' +test_expect_success 'clone does not keep pack' ' + + rm -fr dst && + git clone -n "file://$(pwd)/src" dst && + ! test -f dst/file && + ! (echo dst/.git/objects/pack/pack-* | grep "\.keep") + +' + test_expect_success 'clone checks out files' ' + rm -fr dst && git clone src dst && test -f dst/file ' +test_expect_success 'clone respects GIT_WORK_TREE' ' + + GIT_WORK_TREE=worktree git clone src bare && + test -f bare/config && + test -f worktree/file + +' + +test_expect_success 'clone creates intermediate directories' ' + + git clone src long/path/to/dst && + test -f long/path/to/dst/file + +' + +test_expect_success 'clone creates intermediate directories for bare repo' ' + + git clone --bare src long/path/to/bare/dst && + test -f long/path/to/bare/dst/config + +' + test_done diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh new file mode 100755 index 0000000000..8367a6845f --- /dev/null +++ b/t/t5602-clone-remote-exec.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description=clone + +. ./test-lib.sh + +test_expect_success setup ' + echo "#!/bin/sh" > not_ssh + echo "echo \"\$*\" > not_ssh_output" >> not_ssh + echo "exit 1" >> not_ssh + chmod +x not_ssh +' + +test_expect_success 'clone calls git-upload-pack unqualified with no -u option' ' + GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk + echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected + test_cmp expected not_ssh_output +' + +test_expect_success 'clone calls specified git-upload-pack with -u option' ' + GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk + echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected + test_cmp expected not_ssh_output +' + +test_done diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index c6be2597f7..2fb672c3b4 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -139,4 +139,6 @@ check_describe "test1-lightweight-*" --tags --match="test1-*" check_describe "test2-lightweight-*" --tags --match="test2-*" +check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^ + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 241c70dc66..acddbf5037 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1067,4 +1067,24 @@ test_expect_success \ test_cmp expect actual ' +test_expect_success 'filename for the message is relative to cwd' ' + mkdir subdir && + echo "Tag message in top directory" >msgfile-5 && + echo "Tag message in sub directory" >subdir/msgfile-5 && + ( + cd subdir && + git tag -a -F msgfile-5 tag-from-subdir + ) && + git cat-file tag tag-from-subdir | grep "in sub directory" +' + +test_expect_success 'filename for the message is relative to cwd' ' + echo "Tag message in sub directory" >subdir/msgfile-6 && + ( + cd subdir && + git tag -a -F msgfile-6 tag-from-subdir-2 + ) && + git cat-file tag tag-from-subdir-2 | grep "in sub directory" +' + test_done diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index 39ba14148c..96d15083fb 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -428,4 +428,51 @@ test_expect_success '--mixed refreshes the index' ' test_cmp expect output ' +test_expect_success 'disambiguation (1)' ' + + git reset --hard && + >secondfile && + git add secondfile && + test_must_fail git reset secondfile && + test -z "$(git diff --cached --name-only)" && + test -f secondfile && + test ! -s secondfile + +' + +test_expect_success 'disambiguation (2)' ' + + git reset --hard && + >secondfile && + git add secondfile && + rm -f secondfile && + test_must_fail git reset secondfile && + test -n "$(git diff --cached --name-only -- secondfile)" && + test ! -f secondfile + +' + +test_expect_success 'disambiguation (3)' ' + + git reset --hard && + >secondfile && + git add secondfile && + rm -f secondfile && + test_must_fail git reset HEAD secondfile && + test -z "$(git diff --cached --name-only)" && + test ! -f secondfile + +' + +test_expect_success 'disambiguation (4)' ' + + git reset --hard && + >secondfile && + git add secondfile && + rm -f secondfile && + test_must_fail git reset -- secondfile && + test -z "$(git diff --cached --name-only)" && + test ! -f secondfile +' + test_done diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index baed6ce96b..823256a246 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -138,4 +138,33 @@ test_expect_success '--signoff' ' diff expect output ' +test_expect_success 'commit message from file (1)' ' + mkdir subdir && + echo "Log in top directory" >log && + echo "Log in sub directory" >subdir/log && + ( + cd subdir && + git commit --allow-empty -F log + ) && + commit_msg_is "Log in sub directory" +' + +test_expect_success 'commit message from file (2)' ' + rm -f log && + echo "Log in sub directory" >subdir/log && + ( + cd subdir && + git commit --allow-empty -F log + ) && + commit_msg_is "Log in sub directory" +' + +test_expect_success 'commit message from stdin' ' + ( + cd subdir && + echo "Log with foo word" | git commit --allow-empty -F - + ) && + commit_msg_is "Log with foo word" +' + test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index ed871a6b4d..c25eff9e46 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -212,7 +212,11 @@ test_expect_success 'do not fire editor in the presence of conflicts' ' # Must fail due to conflict test_must_fail git cherry-pick -n master && echo "editor not started" >.git/result && - test_must_fail GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" git commit && + ( + GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" && + export GIT_EDITOR && + test_must_fail git commit + ) && test "$(cat .git/result)" = "editor not started" ' diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index d21cd290d3..daf45b7ffa 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -222,36 +222,12 @@ test_expect_success 'setup' ' test_debug 'gitk --all' test_expect_success 'test option parsing' ' - if git merge -$ c1 - then - echo "[OOPS] -$ accepted" - false - fi && - if git merge --no-such c1 - then - echo "[OOPS] --no-such accepted" - false - fi && - if git merge -s foobar c1 - then - echo "[OOPS] -s foobar accepted" - false - fi && - if git merge -s=foobar c1 - then - echo "[OOPS] -s=foobar accepted" - false - fi && - if git merge -m - then - echo "[OOPS] missing commit msg accepted" - false - fi && - if git merge - then - echo "[OOPS] missing commit references accepted" - false - fi + test_must_fail git merge -$ c1 && + test_must_fail git merge --no-such c1 && + test_must_fail git merge -s foobar c1 && + test_must_fail git merge -s=foobar c1 && + test_must_fail git merge -m && + test_must_fail git merge ' test_expect_success 'merge c0 with c1' ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 6b0483f3e9..6b0483f3e9 100644..100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh new file mode 100755 index 0000000000..c18878fad1 --- /dev/null +++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright (c) 2008 Jan Krüger +# + +test_description='git-svn respects rewriteRoot during rebuild' + +. ./lib-git-svn.sh + +mkdir import +cd import + touch foo + svn import -m 'import for git-svn' . "$svnrepo" >/dev/null +cd .. +rm -rf import + +test_expect_success 'init, fetch and checkout repository' ' + git svn init --rewrite-root=http://invalid.invalid/ "$svnrepo" && + git svn fetch + git checkout -b mybranch remotes/git-svn + ' + +test_expect_success 'remove rev_map' ' + rm "$GIT_SVN_DIR"/.rev_map.* + ' + +test_expect_success 'rebuild rev_map' ' + git svn rebase >/dev/null + ' + +test_done + diff --git a/test-parse-options.c b/test-parse-options.c index 73360d7512..2a79e729a4 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -2,9 +2,22 @@ #include "parse-options.h" static int boolean = 0; -static int integer = 0; +static unsigned long integer = 0; +static int abbrev = 7; +static int verbose = 0, dry_run = 0, quiet = 0; static char *string = NULL; +int length_callback(const struct option *opt, const char *arg, int unset) +{ + printf("Callback: \"%s\", %d\n", + (arg ? arg : "not set"), unset); + if (unset) + return 1; /* do not support unset */ + + *(unsigned long *)opt->value = strlen(arg); + return 0; +} + int main(int argc, const char **argv) { const char *usage[] = { @@ -13,15 +26,29 @@ int main(int argc, const char **argv) }; struct option options[] = { OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"), + OPT_BIT('4', "or4", &boolean, + "bitwise-or boolean with ...0100", 4), + OPT_GROUP(""), OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"), - OPT_GROUP("string options"), + OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), + OPT_DATE('t', NULL, &integer, "get timestamp of <time>"), + OPT_CALLBACK('L', "length", &integer, "str", + "get length of <str>", length_callback), + OPT_GROUP("String options"), OPT_STRING('s', "string", &string, "string", "get a string"), OPT_STRING(0, "string2", &string, "str", "get another string"), OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), OPT_STRING('o', NULL, &string, "str", "get another string"), - OPT_GROUP("magic arguments"), + OPT_SET_PTR(0, "default-string", &string, + "set string to default", (unsigned long)"default"), + OPT_GROUP("Magic arguments"), OPT_ARGUMENT("quux", "means --quux"), + OPT_GROUP("Standard options"), + OPT__ABBREV(&abbrev), + OPT__VERBOSE(&verbose), + OPT__DRY_RUN(&dry_run), + OPT__QUIET(&quiet), OPT_END(), }; int i; @@ -29,8 +56,12 @@ int main(int argc, const char **argv) argc = parse_options(argc, argv, options, usage, 0); printf("boolean: %d\n", boolean); - printf("integer: %d\n", integer); + printf("integer: %lu\n", integer); printf("string: %s\n", string ? string : "(not set)"); + printf("abbrev: %d\n", abbrev); + printf("verbose: %d\n", verbose); + printf("quiet: %s\n", quiet ? "yes" : "no"); + printf("dry run: %s\n", dry_run ? "yes" : "no"); for (i = 0; i < argc; i++) printf("arg %02d: %s\n", i, argv[i]); diff --git a/transport.c b/transport.c index 3ff851935f..b3e3e61f9d 100644 --- a/transport.c +++ b/transport.c @@ -463,17 +463,14 @@ static struct ref *get_refs_via_curl(struct transport *transport) run_active_slot(slot); if (results.curl_result != CURLE_OK) { strbuf_release(&buffer); - if (missing_target(&results)) { - return NULL; - } else { - error("%s", curl_errorstr); - return NULL; - } + if (missing_target(&results)) + die("%s not found: did you run git update-server-info on the server?", refs_url); + else + die("%s download error - %s", refs_url, curl_errorstr); } } else { strbuf_release(&buffer); - error("Unable to start request"); - return NULL; + die("Unable to start HTTP request"); } data = buffer.buf; @@ -645,7 +642,9 @@ static int fetch_refs_via_pack(struct transport *transport, args.lock_pack = 1; args.use_thin_pack = data->thin; args.include_tag = data->followtags; - args.verbose = transport->verbose > 0; + args.verbose = (transport->verbose > 0); + args.quiet = args.no_progress = (transport->verbose < 0); + args.no_progress = !isatty(1); args.depth = data->depth; for (i = 0; i < nr_heads; i++) diff --git a/tree-diff.c b/tree-diff.c index e1e2e6c6ce..bbb126fc46 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -15,6 +15,15 @@ static char *malloc_base(const char *base, int baselen, const char *path, int pa return newbase; } +static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen) +{ + char *fullname = xmalloc(baselen + pathlen + 1); + memcpy(fullname, base, baselen); + memcpy(fullname + baselen, path, pathlen); + fullname[baselen + pathlen] = 0; + return fullname; +} + static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen); @@ -24,6 +33,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; + char *fullname; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -55,15 +65,20 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { int retval; char *newbase = malloc_base(base, baselen, path1, pathlen1); - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { + newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, base, path1); + sha1, sha2, newbase); + newbase[baselen + pathlen1] = '/'; + } retval = diff_tree_sha1(sha1, sha2, newbase, opt); free(newbase); return retval; } - opt->change(opt, mode1, mode2, sha1, sha2, base, path1); + fullname = malloc_fullname(base, baselen, path1, pathlen1); + opt->change(opt, mode1, mode2, sha1, sha2, fullname); + free(fullname); return 0; } @@ -205,10 +220,10 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree unsigned mode; const char *path; const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode); + int pathlen = tree_entry_len(path, sha1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) { enum object_type type; - int pathlen = tree_entry_len(path, sha1); char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; @@ -224,7 +239,9 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree free(tree); free(newbase); } else { - opt->add_remove(opt, prefix[0], mode, sha1, base, path); + char *fullname = malloc_fullname(base, baselen, path, pathlen); + opt->add_remove(opt, prefix[0], mode, sha1, fullname); + free(fullname); } } |