Code

Merge branch 'lt/config-fsync' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 7 Aug 2008 01:56:23 +0000 (18:56 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 7 Aug 2008 18:40:29 +0000 (11:40 -0700)
* lt/config-fsync:
  Add config option to enable 'fsync()' of object files
  Split up default "i18n" and "branch" config parsing into helper routines
  Split up default "user" config parsing into helper routine
  Split up default "core" config parsing into helper routine

166 files changed:
Documentation/RelNotes-1.5.2.txt
Documentation/RelNotes-1.5.3.txt
Documentation/RelNotes-1.5.4.4.txt
Documentation/RelNotes-1.5.4.5.txt
Documentation/RelNotes-1.5.4.6.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.5.5.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.6.1.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.6.2.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.6.3.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.6.4.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.6.5.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/diff-generate-patch.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-check-attr.txt
Documentation/git-cherry-pick.txt
Documentation/git-cherry.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-count-objects.txt
Documentation/git-cvsimport.txt
Documentation/git-cvsserver.txt
Documentation/git-describe.txt
Documentation/git-diff-tree.txt
Documentation/git-fetch.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-format-patch.txt
Documentation/git-hash-object.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-mailinfo.txt
Documentation/git-mailsplit.txt
Documentation/git-merge-one-file.txt
Documentation/git-merge.txt
Documentation/git-mktree.txt
Documentation/git-name-rev.txt
Documentation/git-peek-remote.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-reflog.txt
Documentation/git-request-pull.txt
Documentation/git-rerere.txt
Documentation/git-reset.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-show-branch.txt
Documentation/git-show.txt
Documentation/git-status.txt
Documentation/git-svn.txt
Documentation/git-symbolic-ref.txt
Documentation/git-tag.txt
Documentation/git-update-server-info.txt
Documentation/git-verify-pack.txt
Documentation/git-whatchanged.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcvs-migration.txt
Documentation/howto/rebase-from-internal-branch.txt
Documentation/howto/rebuild-from-update-hook.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/howto/separating-topic-branches.txt
Documentation/howto/update-hook-example.txt
Documentation/pretty-formats.txt
Documentation/rev-list-options.txt
Documentation/technical/api-builtin.txt
Documentation/technical/api-parse-options.txt
Documentation/technical/api-run-command.txt
GIT-VERSION-GEN
Makefile
RelNotes
attr.c
builtin-cat-file.c
builtin-checkout.c
builtin-clone.c
builtin-commit.c
builtin-describe.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-for-each-ref.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-mailinfo.c
builtin-merge-recursive.c
builtin-name-rev.c
builtin-reflog.c
builtin-reset.c
builtin-rev-list.c
builtin-revert.c
builtin-rm.c
builtin-send-pack.c
builtin-tag.c
builtin-upload-archive.c
cache.h
combine-diff.c
commit.c
contrib/completion/git-completion.bash
convert.c
daemon.c
diff-lib.c
diff.c
diff.h
git-add--interactive.perl
git-am.sh
git-cvsimport.perl
git-cvsserver.perl
git-merge.sh
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
git-submodule.sh
git-svn.perl
http-walker.c
http.c
http.h
index-pack.c
parse-options.c
parse-options.h
path.c
pretty.c
read-cache.c
refs.c
remote.c
revision.c
revision.h
run-command.c
setup.c
sha1_file.c
shell.c
t/t0001-init.sh
t/t0004-unwritable.sh
t/t0040-parse-options.sh
t/t1301-shared-repo.sh
t/t1502-rev-parse-parseopt.sh
t/t2103-update-index-ignore-missing.sh [new file with mode: 0755]
t/t3202-show-branch-octopus.sh [new file with mode: 0755]
t/t3600-rm.sh
t/t4017-diff-retval.sh
t/t4202-log.sh
t/t5000-tar-tree.sh
t/t5100-mailinfo.sh
t/t5100/0010 [new file with mode: 0644]
t/t5100/info0010 [new file with mode: 0644]
t/t5100/msg0010 [new file with mode: 0644]
t/t5100/patch0010 [new file with mode: 0644]
t/t5100/sample.mbox
t/t5304-prune.sh [changed mode: 0644->0755]
t/t5404-tracking-branches.sh
t/t5513-fetch-track.sh [new file with mode: 0755]
t/t5601-clone.sh
t/t5602-clone-remote-exec.sh [new file with mode: 0755]
t/t6120-describe.sh
t/t7004-tag.sh
t/t7102-reset.sh
t/t7500-commit.sh
t/t7502-commit.sh
t/t7600-merge.sh
t/t7610-mergetool.sh [changed mode: 0644->0755]
t/t9123-git-svn-rebuild-with-rewriteroot.sh [new file with mode: 0755]
test-parse-options.c
transport.c
tree-diff.c

index 6195715dc78a26ce9ac452bd64852455fb79137c..e8328d090a438e496ff2e6a2026f633d77f589b5 100644 (file)
@@ -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
index d03894b92645f2dd0d7cb464d3ab1905d8cb62ed..0668d3c0cadc8e252ae07e0f873f603fafa02c27 100644 (file)
@@ -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.
index 89fa6d03bc038d6210e94d7fe9fbbffdbc84d883..323c1a88c7fe2be146d2ae7682de6f723acd6fa8 100644 (file)
@@ -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
index 02823413987d5a10364d936327e3a1cfb38cbac2..bbd130e36d411e70f7c3b3b4fcfe531d383e9f0e 100644 (file)
@@ -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 (file)
index 0000000..3e3c3e5
--- /dev/null
@@ -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 (file)
index 0000000..30fa361
--- /dev/null
@@ -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 (file)
index 0000000..4864b16
--- /dev/null
@@ -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 (file)
index 0000000..5902a85
--- /dev/null
@@ -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 (file)
index 0000000..9426112
--- /dev/null
@@ -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 (file)
index 0000000..d8968f1
--- /dev/null
@@ -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 (file)
index 0000000..47ca172
--- /dev/null
@@ -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.
index 2466ecfc6b2be075e88c1b1a48e814c726e228f5..da2cb3f9f45899b780785b18512a5af4c3fbf263 100644 (file)
@@ -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"]
@@ -562,9 +562,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
index 029c5f2b82c5bece3fa4a9e6e87b83c517e0c7f6..517e1eba3c56907ebcb1d478dceb184e53fceda4 100644 (file)
@@ -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):
index b8e3fa67598037bc5d0de30818b977048bbada72..815864c37fb42dd6c859253aa219685fca242f47 100644 (file)
@@ -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:
index 46544a07694a90db908729b6badf92370f37226b..5622971f6a1fe6ead3eda29a3bb80b2f08aa15f0 100644 (file)
@@ -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
 --------------
index 8f4fb46685624d07f5940eb973a7fd03aefb5aa0..0e0196e5b0ce51b03526b07d539c7071eb0f0e7b 100644 (file)
@@ -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
 ---
index 0fd58083eb2afdb7fed7ebf01bab3b5e1cae1421..39cd5d961f4696c36b3050c880af413c95da9282 100644 (file)
@@ -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
 --------------
index ef16b93982f92dd0bc567a3c9bdeaa7703eeac3a..f8e1bd5027eeb3538d8f38fcf1c4ab0fb10b4b21 100644 (file)
@@ -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
 --------------
index 5ac9cfb0ef2e2eb26ebe5cce6a5c7ed54d4e39ec..44e7749b107d5e809dbbb15e3fde4471e5734f7a 100644 (file)
@@ -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
 --------------
index ef7caf61e1d344ea447b0b874063cabc0a83fdec..912601160cffb3ff8d41509a73109d9ddd0a076d 100644 (file)
@@ -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
 --------------
index 7e8b4ff72c0192f01523118b9a8caeddbcbda09c..861ce93a49fcfd6498344c107c32c39f26cf8b00 100644 (file)
@@ -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
index c90421ee7f3b6a3fe1f08c4868b5652d4d7db569..b0f20e23925d1df9907a58b596b2f096c5ef53ee 100644 (file)
@@ -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
index 1ba85a259a2d8896b5634f3496542b5561dbf2de..4a9dcd7382954faf22dec6b7d2e6d33b2115532b 100644 (file)
@@ -27,7 +27,7 @@ OPTIONS
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
index 2f9b35f6229143f566f31e1ef6de290572181608..93b7d2dc998f9e7c8bedf39f686b81c95deffa6c 100644 (file)
@@ -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
 -------
index 3310ae25ff75c302e6b9088a0807aee340ad69c7..19da87e71d252e666335de7c97a5abcdd5fadbf8 100644 (file)
@@ -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
index 9f6f4831864a3112119bc7d7fec22aa7a72225e5..44aaa4090c291effcf863defdbf80f20f30d2bdc 100644 (file)
@@ -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
index 56caeb2d26f2f8eab1234be6f146201ded5b098a..5d23985b570280baf30746f9749751aa079c7e76 100644 (file)
@@ -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
index 489b2b17e69c0a0f6b2df0ce4b2da6f38f809546..4fae7fb5a8ad3cf5c5efd14b3c99c25cbc88c77f 100644 (file)
@@ -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
 -------------
index 2a7cfb980b7f0b6fa2bd741b3601467f07025691..222052fba740a3baf4add6c3369bff17097808f2 100644 (file)
@@ -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
 --------------
index 4dafa39a9211d9d35498f4c88418713b1aa33284..ee27eff3b1139f54784876cac0a61d6b6383f37e 100644 (file)
@@ -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
 --------------
index cf3dce8a4a77d480a719260b7c8549c16f7c8e17..1abcd96c6db786e90a4eeaf193f7575bbab7b6ab 100644 (file)
@@ -37,7 +37,7 @@ OPTIONS
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
index f92f3ca1860f9d3e0d5b3f21674a9c2baf61b4d9..f282164e9bb3d724c9904ca94da7757fe98cb8b2 100644 (file)
@@ -69,7 +69,7 @@ EXAMPLES
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
index d9881fbbbedb84f400bf0b630dcb60acd5ad4e9e..8955b71302ee387a955c3ffc67545be396fef934 100644 (file)
@@ -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
index 183dc1dd75c1268b199257496ac778e0d5dd7743..0b23faee7a431f6b68056a1517a099c9689fc56e 100644 (file)
@@ -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
index 9a2aedd480c24018d12bde419b69f865be2b8825..1a0df38d5bd9571b70eb47f50bfc114b38632973 100644 (file)
@@ -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
index 5c9ce641ec814a980b9a5d32291cccba32a0cc8b..546ebe8bf02616413f4d3b99528909270aae34a6 100644 (file)
@@ -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
 --------------
index 55bc3674797366496d7c1ca1f5b6564b06c01de1..b05e0cee11352335cbeb1899e8d6cb7070395e37 100644 (file)
@@ -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
index 1ddbf00afccf93d2c31d3c6d0deabd82ff4fe779..6927eb9950ecfb07a5e4fc7bffb48aae2dc8219f 100644 (file)
@@ -23,7 +23,7 @@ OPTIONS
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
index ffac3f8f564bf5f5e2ca317b986db9b01f5dc026..83d8e4a9fc9757d9c666c3c122978747506b7d6e 100644 (file)
@@ -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,
index ffbf93a7993cee0386c42bef1c827a8488f04d8e..3fb17f9d7f10fab15c31066e64d93e8c66d5c510 100644 (file)
@@ -39,7 +39,7 @@ OPTIONS
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
index d0f1595f7e9051b5d58d1dba030ea3a7d80bdab5..c731bdc07e0118dd12a30bb2e3c3513bd8e24803 100644 (file)
@@ -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
 --------------
index 89e0049bce1367f308c58d3306266f93a6cd7b75..82dd4433f2ac3113fce65f4aa3a953f020bbd1e1 100644 (file)
@@ -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
index 7166414355e7469c5aeae0262f3902ce7398c989..b7e1da000c6d6aa91b4557daa3dbce76b1672a20 100644 (file)
@@ -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
index 8492aeacf1823bed947d4dc318f45e2488cac574..c9c25f333718f1873f28eb3ded45a87cb5088c20 100644 (file)
@@ -94,7 +94,7 @@ them.
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
index c71d86985ea2136e7c7da5e4ca758ca7ef675409..70810c01d47f16d4595675514a5e0d84496ecc15 100644 (file)
@@ -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
 --------------
index 8030ec4d01de8cf2c7a62a7b1fd8d917e6d14b53..37828e5c5ab83ec1d17747e61703bd8aaa457c8a 100644 (file)
@@ -204,7 +204,7 @@ conflict.
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
index 12ea9b23c5b55366f142319451bb45db4e10affe..0b368b39eef1808ec5f8becb3664af22329b8b69 100644 (file)
@@ -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
 --------------
index 9e273bc5a6ee091ad7b81254228d33fd4df5541e..9082fc991be760e385e162ba6d118911c659955f 100644 (file)
@@ -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
 --------------
index 5b49b813862c5318701e40f1a798ca04cd1d3a63..5fdeaff9944e14fb8a497bce8327fbf2cc530fe0 100644 (file)
@@ -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
 --------------
index de9e8f885f794692bcc45b871e791ebbd7c806cd..6f4a2c43069f9d0877b341159b315943a5757304 100644 (file)
@@ -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
index baaf2bc8feefe4fb88a1ec43d2f70bbfdfe6fbf6..1017391f7c569dc87cdf5055aaebcacb3402bfbc 100644 (file)
@@ -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>.
 
 
index fef62b16df365301f01f4c129fdba02fef84234a..6026e8b84bcdf206da12820af5f657667c6bee66 100644 (file)
@@ -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
 --------------
index f4cbd2f212e544f0a17c761a4c870a925db5802b..c350ad0f83b413fa4c7810195f64cdfbbfdd1717 100644 (file)
@@ -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
index 3d3a059c5e2e91bff2de173c5d6f8107d10b7e62..5709dee20835e1b8c2f7832632f5f6184be2984b 100644 (file)
@@ -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
 ---
index 8f40f4bf0df8bb8db58830e32d85964542d6cd6a..6cf11ce6481aa850f3b979b3feda04ae8f7cba48 100644 (file)
@@ -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
 --------------
index d21be41d0646c80e7ec9aeb1ed46ce617022e3cc..4fd7b5edf902e2e214975caaf743df79a8f987a6 100644 (file)
@@ -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
 --------------
index 478f236996eac55c8142d48de8bda1456b426d4a..ff704bd93f00862407c74c4e35e8723bc65acc13 100644 (file)
@@ -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
 --------------
index f5d39c7870b9f6d07c8fadd3823df5d56da2dfe0..fb672ea0fc34bb5fe78c4ca0e41736baccc437da 100644 (file)
@@ -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
index 7414238fe52819689615e57d10f53dd2b29a3cbe..0f55f8005b651a5df9ec56c8b42c55ed6dfa1f08 100644 (file)
@@ -43,12 +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.6/git.html[documentation for release 1.5.6]
+* link:v1.5.6.5/git.html[documentation for release 1.5.6.5]
 
 * release notes for
-  link:RelNotes-1.5.6.txt[1.5.6],
+  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/git.html[documentation for release 1.5.5]
+* 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],
@@ -57,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
@@ -82,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],
index 471754eb12afa5862aa9c5e88ed3bfd2ee5cac7f..ef06d94ca8dd57762fcefe3b87921799d49dffb6 100644 (file)
@@ -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
 ---
index 1db3f5294527e07576d44cb3a7bff384871fc24e..0325d6759d5ee329f284dac625ef4c40c31082c7 100644 (file)
@@ -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
 -------------------------------------
 
index 7a76045eb742b38e726e15491db2bf4315cb8f6a..d214d4bf9d0e539c6bf58ba24dcd12aabbaea1d8 100644 (file)
@@ -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
index 8d55dfbfaef7ef6bb30b65ea52c7825b099b50d8..48c67568d3418b2d6608f362f4b76e02ec450abc 100644 (file)
@@ -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
index 865a6663240f744d448b0a125ebc123afb72ede2..e70d8a31e7b05e8efc70c6a56f476324065d57a6 100644 (file)
@@ -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
index 0d73b31224c881eb83f30ec3c5421a81288f6502..6d3eb8ed00e1779efce8abe201d37c8cff07ec29 100644 (file)
@@ -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.
 
index 88765b55754488223cfe492a83afd1aed5380e61..3ef7c0d908d6c4d98d5d698587fa0fafb2cfa335 100644 (file)
@@ -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/*)
index ec3755579408ebae58c7de644609590f5636b9c6..c11d4957714db202a012209e2437b9e050a28ae0 100644 (file)
@@ -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
index 37dd1d61ea36d7afb1e1b16cc46bee0d357ad1c8..f69260f4c04a83d4cdae2be733887bce63a6aa5d 100644 (file)
@@ -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::
 
index 52cdb4c5201b7971ba908c35722e4914f408fbec..7ede1e64e5d40ec8f742e900d7273d6f961605e2 100644 (file)
@@ -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
index b7cda94f54962b185da33fcddf3e033c1e18c5ae..539863b1f920f8f34ad9272907cbacbd35a7fcbd 100644 (file)
@@ -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.
index 3e1342acf405adb322054a19123cd98fc12b69a9..75aa5d49234ec36857a7c8d2f3900001af5cbcde 100644 (file)
@@ -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
index f221447478aea8628c0ab6d098338f7e8630201e..445dca3ffcb7074dc58ee41d971c1164e97ee14f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.6.GIT
+DEF_VER=v1.5.6.5.GIT
 
 LF='
 '
index b003e3e60a1aecae27497d941d211849bedec02b..f13184b2ba7dcd4dc7f6ab9eb0652550874d843a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
index e29d6504d9e8fe45d3f7ff7f82f1e8f1f57b9f6f..1c0163594aeb2a323c8a0cb8965a5e3d8947ee2c 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -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
diff --git a/attr.c b/attr.c
index 0fb47d34346ca96addde5cb3722fa5e586057285..17f6a4dca521d9690377f2e93a0192d8a874d2ad 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -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);
index bd343efae7d6cc6fddef4df5c3433b97bd640d3c..880e75af5e1951689a417aa47e64f99a20d46ae6 100644 (file)
@@ -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;
index 93ea69bfaa083f49a6e808c7317ea1910b29c847..aec2bc6f8d71a41e9d1cb718a498bfea08b767c3 100644 (file)
@@ -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))
index 71909520710ab046fe04723f5a25ac9a53374025..863b22eeb2d22f031a9243155ba9df7be9a3b119 100644 (file)
@@ -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;
index 90200ed643bcf21f28a66396f0d15db920a5d4c8..0c6d1f4f455fb3832809f03fd2748feea143006a 100644 (file)
@@ -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);
 
index 3da99c1d06f1eeb85e760036dc881282558603d6..e515f9ca9b5d0ec13e96a7866e27bdd9e852b435 100644 (file)
@@ -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;
        }
index de1e8d1365769c7c841749901f705c0b6a78eab3..6e98cafd08ca9fb09d4f860878691db9ec4999ba 100644 (file)
@@ -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;
index e81ee2d02b588c83f9ac355d20559271be73871d..97fdc51e3188143e0546512f59be9d2542dcac9a 100644 (file)
@@ -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;
 }
index 07d9c572125523e2eb8f82e4cab907ee7dc94348..fef93d7488d15fac28e96f887f26556755cc6ca8 100644 (file)
@@ -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;
+               }
        }
 }
 
index ef299108f529fa5fa931d765828f04535c3a6351..d8b06ce810d334654ada4b7fa3b79c19a4787565 100644 (file)
@@ -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";
index e23b8438c741651f48bbf529f89d0336cc718fed..c68a3b1e7409cb15879724d9acef1cecc97ab9fe 100644 (file)
@@ -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] != '/') {
index 9817d6fbeb69393ed321e71b6211a8630b982fab..430d87661e37a4b08963de1ee5c31b8143ebc373 100644 (file)
@@ -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);
index 97c1ff97440ec107e336df774f86aadc28f26b89..13f0502b9e0bca9e4119896c01786b99cc54441e 100644 (file)
@@ -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)
 {
index 4aa28a1babbb275df8110fd80311f34a12fea750..43bf6aa45eeacbb67490c809070f40023ce4e434 100644 (file)
@@ -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);
index f153da012f4e89ff8744ede70911cd4690de79b2..5352bc87b9ab5177922039cfec48a2fda8bd50a6 100644 (file)
@@ -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;
index b151e24ff94e06840db7e57014fe4a73ea811575..125d455b97ca499806ff417871ab6ce7aad922c5 100644 (file)
@@ -269,7 +269,9 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
        int status = 0;
 
        memset(&cb, 0, sizeof(cb));
-       /* we take the lock for the ref itself to prevent it from
+
+       /*
+        * we take the lock for the ref itself to prevent it from
         * getting updated.
         */
        lock = lock_any_ref_for_update(ref, sha1, 0);
@@ -331,21 +333,130 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused
        return 0;
 }
 
-static int reflog_expire_config(const char *var, const char *value, void *cb)
+static struct reflog_expire_cfg {
+       struct reflog_expire_cfg *next;
+       unsigned long expire_total;
+       unsigned long expire_unreachable;
+       size_t len;
+       char pattern[FLEX_ARRAY];
+} *reflog_expire_cfg, **reflog_expire_cfg_tail;
+
+static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
 {
-       if (!strcmp(var, "gc.reflogexpire")) {
-               if (!value)
-                       config_error_nonbool(var);
-               default_reflog_expire = approxidate(value);
+       struct reflog_expire_cfg *ent;
+
+       if (!reflog_expire_cfg_tail)
+               reflog_expire_cfg_tail = &reflog_expire_cfg;
+
+       for (ent = reflog_expire_cfg; ent; ent = ent->next)
+               if (ent->len == len &&
+                   !memcmp(ent->pattern, pattern, len))
+                       return ent;
+
+       ent = xcalloc(1, (sizeof(*ent) + len));
+       memcpy(ent->pattern, pattern, len);
+       ent->len = len;
+       *reflog_expire_cfg_tail = ent;
+       reflog_expire_cfg_tail = &(ent->next);
+       return ent;
+}
+
+static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
+{
+       if (!value)
+               return config_error_nonbool(var);
+       if (!strcmp(value, "never") || !strcmp(value, "false")) {
+               *expire = 0;
                return 0;
        }
-       if (!strcmp(var, "gc.reflogexpireunreachable")) {
-               if (!value)
-                       config_error_nonbool(var);
-               default_reflog_expire_unreachable = approxidate(value);
+       *expire = approxidate(value);
+       return 0;
+}
+
+/* expiry timer slot */
+#define EXPIRE_TOTAL   01
+#define EXPIRE_UNREACH 02
+
+static int reflog_expire_config(const char *var, const char *value, void *cb)
+{
+       const char *lastdot = strrchr(var, '.');
+       unsigned long expire;
+       int slot;
+       struct reflog_expire_cfg *ent;
+
+       if (!lastdot || prefixcmp(var, "gc."))
+               return git_default_config(var, value, cb);
+
+       if (!strcmp(lastdot, ".reflogexpire")) {
+               slot = EXPIRE_TOTAL;
+               if (parse_expire_cfg_value(var, value, &expire))
+                       return -1;
+       } else if (!strcmp(lastdot, ".reflogexpireunreachable")) {
+               slot = EXPIRE_UNREACH;
+               if (parse_expire_cfg_value(var, value, &expire))
+                       return -1;
+       } else
+               return git_default_config(var, value, cb);
+
+       if (lastdot == var + 2) {
+               switch (slot) {
+               case EXPIRE_TOTAL:
+                       default_reflog_expire = expire;
+                       break;
+               case EXPIRE_UNREACH:
+                       default_reflog_expire_unreachable = expire;
+                       break;
+               }
                return 0;
        }
-       return git_default_config(var, value, cb);
+
+       ent = find_cfg_ent(var + 3, lastdot - (var+3));
+       if (!ent)
+               return -1;
+       switch (slot) {
+       case EXPIRE_TOTAL:
+               ent->expire_total = expire;
+               break;
+       case EXPIRE_UNREACH:
+               ent->expire_unreachable = expire;
+               break;
+       }
+       return 0;
+}
+
+static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
+{
+       struct reflog_expire_cfg *ent;
+
+       if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
+               return; /* both given explicitly -- nothing to tweak */
+
+       for (ent = reflog_expire_cfg; ent; ent = ent->next) {
+               if (!fnmatch(ent->pattern, ref, 0)) {
+                       if (!(slot & EXPIRE_TOTAL))
+                               cb->expire_total = ent->expire_total;
+                       if (!(slot & EXPIRE_UNREACH))
+                               cb->expire_unreachable = ent->expire_unreachable;
+                       return;
+               }
+       }
+
+       /*
+        * If unconfigured, make stash never expire
+        */
+       if (!strcmp(ref, "refs/stash")) {
+               if (!(slot & EXPIRE_TOTAL))
+                       cb->expire_total = 0;
+               if (!(slot & EXPIRE_UNREACH))
+                       cb->expire_unreachable = 0;
+               return;
+       }
+
+       /* Nothing matched -- use the default value */
+       if (!(slot & EXPIRE_TOTAL))
+               cb->expire_total = default_reflog_expire;
+       if (!(slot & EXPIRE_UNREACH))
+               cb->expire_unreachable = default_reflog_expire_unreachable;
 }
 
 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
@@ -353,6 +464,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
        struct cmd_reflog_expire_cb cb;
        unsigned long now = time(NULL);
        int i, status, do_all;
+       int explicit_expiry = 0;
 
        git_config(reflog_expire_config, NULL);
 
@@ -367,20 +479,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
        cb.expire_total = default_reflog_expire;
        cb.expire_unreachable = default_reflog_expire_unreachable;
 
-       /*
-        * We can trust the commits and objects reachable from refs
-        * even in older repository.  We cannot trust what's reachable
-        * from reflog if the repository was pruned with older git.
-        */
-
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
                        cb.dry_run = 1;
-               else if (!prefixcmp(arg, "--expire="))
+               else if (!prefixcmp(arg, "--expire=")) {
                        cb.expire_total = approxidate(arg + 9);
-               else if (!prefixcmp(arg, "--expire-unreachable="))
+                       explicit_expiry |= EXPIRE_TOTAL;
+               }
+               else if (!prefixcmp(arg, "--expire-unreachable=")) {
                        cb.expire_unreachable = approxidate(arg + 21);
+                       explicit_expiry |= EXPIRE_UNREACH;
+               }
                else if (!strcmp(arg, "--stale-fix"))
                        cb.stalefix = 1;
                else if (!strcmp(arg, "--rewrite"))
@@ -400,6 +510,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                else
                        break;
        }
+
+       /*
+        * We can trust the commits and objects reachable from refs
+        * even in older repository.  We cannot trust what's reachable
+        * from reflog if the repository was pruned with older git.
+        */
        if (cb.stalefix) {
                init_revisions(&cb.revs, prefix);
                if (cb.verbose)
@@ -417,6 +533,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                for_each_reflog(collect_reflog, &collected);
                for (i = 0; i < collected.nr; i++) {
                        struct collected_reflog *e = collected.e[i];
+                       set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
                        status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
                        free(e);
                }
@@ -430,6 +547,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                        status |= error("%s points nowhere!", ref);
                        continue;
                }
+               set_reflog_expiry_param(&cb, explicit_expiry, ref);
                status |= expire_reflog(ref, sha1, 0, &cb);
        }
        return status;
index f34acb1915a7bdbe41113febc90283bc94d0dc1f..a0321694c5c3d5798d28f8fe14493652e0dd0054 100644 (file)
@@ -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. */
index 83a7b1349e06dbf1a355888272d9b13a7d4c22c4..39ec61c42858c0b1c5306025f0962b3ee3d7f910 100644 (file)
@@ -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);
 
        }
index 0270f9b85a8229d30ab3fab5ce73661f383b005e..bde28b2c4df9e0d79589a594a8d93103a4f7bd39 100644 (file)
@@ -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);
index 22c9bd1c6cf2d372e0262506cc1e21daebdf579a..abdab7f001587e819aecb5c5f7e8dcbb10a5dd48 100644 (file)
@@ -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++)
index d76260c09eef064d8a2862b5d6f0e826d968d643..a708d0af48e210fd4439c336c2faa3e7400b5fa4 100644 (file)
@@ -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);
index e675206de38f0709b4c07e1667d791bf9b6704cb..3bd019cc566aad3137a2c0a50a2e176003d9a442 100644 (file)
@@ -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;
index 48ae09e9b5268ce1f11cfba433680a147ca39f7e..371400d49a5ff9f6ce297d7af07eb3fd6426c9ee 100644 (file)
@@ -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 */
diff --git a/cache.h b/cache.h
index 01c8502afb3afe19b59ea2dad8cf64e154aa3612..882265122665fe2a876e8b23e3ec6899cd0faa23 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -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 {
@@ -519,6 +519,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)
 {
@@ -526,6 +527,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 *);
index 588c58bc55dfe78998d40a4dcce2a7b6ea6f7f5a..9f80a1c5e3a461afd11966625589684d61187911 100644 (file)
@@ -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++) {
index e2d8624d9c19adde87ae521361f4ccd8260c06a0..09cf167423ee88f0b4e8117dd3e0a2bd8ccda887 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -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;
        }
index 2141b6b6ba4cfed2c2ea3beca1e1149d489b75fa..72f02f208fad95128d7e2fd3b55fdddd23bf2460 100755 (executable)
 #       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=""
index 1c66844783ec3baa1373b3f0c41ea080bc7354fe..352b69d4ceeec411a81469a6146e023aa1d6b338 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -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)) {
index 63cd12cd9c1909edbaab49aea066ff6fe03c3542..ce3a6f58f3c5c6bb88617510422c4053e0d545a2 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -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) {
index b17722d66a7008b822125bb96ab1b7921e8b627b..e7eaff9a68ccbcc692522c9956f0dae9af45f3f1 100644 (file)
@@ -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;
 }
 
diff --git a/diff.c b/diff.c
index 526249008662d4041e5623914c1a420f3443c4d4..342733ba7324b59f8cf1ec29f92a1dae43198913 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -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)
@@ -1150,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);
@@ -3358,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))
@@ -3382,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;
@@ -3405,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)
@@ -3420,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))
diff --git a/diff.h b/diff.h
index 5dc0cb595b64868ca8b8e26e5311d2df102c89e0..50fb5ddb0bec02b0cd5498d6ecc37d44bf874476 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -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,
index 903953e68e98535e754b5a5dd6ba22eb6074ef20..709caa9055e139731bedd8b4e0b2659df6017bfa 100755 (executable)
@@ -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;
index 2c517ede590c5c3274b03d1c980f9a847cc7d643..83b277acfdeafa1f745c3c96bc10eef320a2d6ec 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -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"
index cacbfc0259fd1ae353117d93e345cd8c4dd41188..7e95fb3740cb631d65c1a0bf07a78e2f75324210 100755 (executable)
@@ -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;
index 920bbe15a3bbc7768d47a2adbc84aa81264e2226..b00d1c29cd3a7d2cd8bbcd7ea4f531e050fcfcb9 100755 (executable)
@@ -1884,7 +1884,7 @@ sub req_annotate
     }
 
     # done; get out of the tempdir
-    cleanupWorkDir();
+    cleanupWorkTree();
 
     print "ok\n";
 
index 5fc5f5201f8ea8e155a25795b93bfea86fc12d12..8026ccff4a459a75148740382646f7fe10b00255 100755 (executable)
@@ -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)
index a64d9d57ab5943ac4e065866ce0ccd7de5364a9a..e3f65bd8808112aebf98f554bd24df38a5e6408c 100755 (executable)
@@ -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
index dd7dfe123c15a4b281c4a25a77887150b4a5dbb5..e2d85eeeab79e60ef46a65cfee1fb4682dd4ba68 100755 (executable)
@@ -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"
index 0b04ba32f0399d338be587ac2d9ad4620705c9a1..385ff7c2197f02207bfa56e2a9b6ec557fbfe0cc 100755 (executable)
@@ -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, $_;
index 3eb78cc724187998aa9ecf71509325631b8668c9..21e5b5b7daf341a59b9496b235adcceafe4f2c8c 100755 (executable)
@@ -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 ' |
index a54979dc51f0fc392b357da9071b6ea19aac4798..a366c891dc9892550093f0bb760d5d2580eb11cd 100755 (executable)
@@ -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) {
index 99f397e32b673e289c2f9d298b1287a97cb7a49e..74033060c4e85b23a947ea5799d8ea96e6040da0 100644 (file)
@@ -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;
diff --git a/http.c b/http.c
index 105dc93843ba1f01ea0d40c63dd174e879f1a25a..1108ab4a3101fb4768cad420ccfdb52d87890a18 100644 (file)
--- a/http.c
+++ b/http.c
@@ -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;
        }
 
diff --git a/http.h b/http.h
index a04fc6a9277945a7084e718753c133ed47d13691..905b4629a47789705c13745fd56ce0c91adea41b 100644 (file)
--- a/http.h
+++ b/http.h
@@ -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);
index 5ac91baf98615d7e494550155c1c4d7665ed2dcd..7d5344abc065dadd6079cc936edc97b6db443b8d 100644 (file)
@@ -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);
index acf3fe3a1a82cd99e7bd6e0ff9d6d3d7e344a155..12c882296e31e90b984aec8afdf5c06d3c213ec5 100644 (file)
@@ -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);
+}
+
index 4ee443dafe146f05d1fe2a46e7e39ca6fdd608f9..13ad15869e356ddaf3eef5a2d80401c39aaaf7d8 100644 (file)
@@ -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
diff --git a/path.c b/path.c
index 7a35a26a1697480f0f43244132d8267deb301651..c1d567996d225c03f58c1208f4806f74f64e92e1 100644 (file)
--- a/path.c
+++ b/path.c
@@ -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];
index 8eb39e915e730ff5039247695adc1e25c14773f4..628a5201c1e8aa3b985bf0b382e5511e17d953d4 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -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 */
index 8e5fbb619295fe3e4d950e8926d8034d6f825e41..f83de8c4158e08bab3e0445c4d15caf2d4d105aa 100644 (file)
@@ -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;
 }
 
diff --git a/refs.c b/refs.c
index 9e8e8581ba981ca88366b614f1e8749cfe8a6ae5..c9bcf148b0e1cd659e645e0f793fc07ebc133426 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -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));
index ff2c8021678fee5ef12060d35c6eb1960e8792c7..5f687b2e298c98e82d775b022743f957fa2fcdfc 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -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);
@@ -963,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)
index fc667552592daa3c894d0df4e97469d1809dbf27..a68abec3f203d751db3eb4bce9c8e958abf3cc9e 100644 (file)
@@ -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;
                }
 
index abce5001f19a60bb15b519b26773b57c83563021..31f08c4056b2f71b56bd7b439450dbba4e750fe9 100644 (file)
@@ -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;
index 44100a749b09439121073e32e7a3143b54185d31..7068ec7e6d74af0cec233259b4b6e41a61ed5123 100644 (file)
@@ -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)
diff --git a/setup.c b/setup.c
index d630e374e7c03b934de14adceb93c9c327796e6d..3b111ea7cf5f68ecca085f5a56421ea190e1771a 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -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;
 }
 
index fe4ee3ece57ae8627572554c1e9af9f292c67ac6..ff3bb493f8950918f9471b1402781f48f1e038ee 100644 (file)
@@ -116,6 +116,15 @@ int safe_create_leading_directories(char *path)
        return 0;
 }
 
+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;
@@ -1600,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"
@@ -2119,6 +2129,7 @@ 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))
                        return -1;
diff --git a/shell.c b/shell.c
index 9826109d5b1b3746aea33dc6b7ebe7b6da19bd22..b27d01c9e4ca51dc3259994da47f4d9a6e8344c3 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -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;
index d31887f9bf35a7fa9e31b1eb859a9cf21c918d6c..c0b781ae49af6cdc8a9bcc4a551310637366eb8f 100755 (executable)
@@ -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
index 9255c63c08f06399525ca098d0374ad7d197e0b7..63e1217e7162435c3da8ec7984b5f6a53b3a10e2 100755 (executable)
@@ -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)
 
 '
index 9965cfa1dca7948f24a835d5beae4608e6947c0a..6309aed4511738b2f68e16974a5a5ceadf2617e5 100755 (executable)
@@ -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
index 6c78c8bc9b76828c258f524e73b40d7daff7c305..dc85e8b60a5c10e57047d1692e383f177e2c478d 100755 (executable)
@@ -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 &&
index d24a47d1149061565822391542c044a7db193ce5..3508d0a612487be824dfe62eaf2377bc05ae8c17 100755 (executable)
@@ -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 (executable)
index 0000000..332694e
--- /dev/null
@@ -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 (executable)
index 0000000..7fe4a6e
--- /dev/null
@@ -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
index f542f0af41989aee51f75b9844abf97943d9e33f..7893d8c40ea510595b0483432e71a74b11b24598 100755 (executable)
@@ -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
index dc0b7126cc996594b415058d83014a2c7d732895..0d0fb87f5732e3ecbca8a195843070539353701e 100755 (executable)
@@ -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
index b53645417b9f4cdf59338f47104acfc3a0c4d702..4c8af45f834d034529c2a627768a0a3e6f1aac8d 100755 (executable)
@@ -71,4 +71,5 @@ test_expect_success 'diff-filter=D' '
 
 
 
-test_done
\ No newline at end of file
+test_done
+
index 9b0baac8db4b342206d37ab5eaff0b7a09d33967..87902f81ef5455290d8a5ff5cf91d39f5004b11b 100755 (executable)
@@ -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' \
index 577ecc210a55a5da10552a4415c4cbb5e321039b..e9f3e72c7ee5584d956d46126956c641a7d53905 100755 (executable)
@@ -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 (file)
index 0000000..f5892c9
--- /dev/null
@@ -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 (file)
index 0000000..1791241
--- /dev/null
@@ -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 (file)
index 0000000..a96c230
--- /dev/null
@@ -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 (file)
index 0000000..f055481
--- /dev/null
@@ -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
+
index 0476b96c33de8bbc6c4b3bc4f510e9fc50aa6440..aba57f922b33b6ab708afbbf82c7e56f6e37bb8d 100644 (file)
@@ -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
+
old mode 100644 (file)
new mode 100755 (executable)
index 1493a92c06d041e502bcc08a1cee95e6758f1775..64fe2615acbd3368536b8a79c0b707561b3e16bd 100755 (executable)
@@ -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/t5513-fetch-track.sh b/t/t5513-fetch-track.sh
new file mode 100755 (executable)
index 0000000..9e74862
--- /dev/null
@@ -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
index 593d1a38772843f1afd67814dcf8920bea3366bc..d785b3df78e8507d81ffa03ff694846791edfc87 100755 (executable)
@@ -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 (executable)
index 0000000..8367a68
--- /dev/null
@@ -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
index c6be2597f73dbd49e6301d01b5ea3c86ac8c34cb..2fb672c3b43a9efe4cb9c85465f6b33f23724e48 100755 (executable)
@@ -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
index 241c70dc66f71d9f53ddc6637e2f813020e740d6..acddbf5037310576e3ee0268e751dd49082cd441 100755 (executable)
@@ -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
index 39ba14148c953d17589450917975372802eecfed..96d15083fb5ac540a0825b8c00dc43c8843a6dec 100755 (executable)
@@ -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
index baed6ce96beb260a32e027dd573313c82202ea7b..823256a246af72285b4d9fecb9ccd77340864a54 100755 (executable)
@@ -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
index ed871a6b4d7963f520b994f4d378b02194d69f9e..c25eff9e468acd628cf0a5e7a0968c801396e9f8 100755 (executable)
@@ -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"
 '
 
index d21cd290d3d8e3d912b94045f3d3d9db8bdd7e7d..daf45b7ffa5bc80a4129a7f4b48dce36711d4c87 100755 (executable)
@@ -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' '
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh
new file mode 100755 (executable)
index 0000000..c18878f
--- /dev/null
@@ -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
+
index 73360d75126af2f231b3cfdad26a47e18fff0a39..2a79e729a4018ddb2da9ff633f4bf3b102fa8f88 100644 (file)
@@ -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]);
index 3ff851935ff8d018a926084b89cb31bbb3d30a07..b3e3e61f9dddec8230532f7d248beba801a38123 100644 (file)
@@ -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++)
index e1e2e6c6ce3c4effffb26e9aed7c6bdd2b00a5ae..bbb126fc46cfb28a0bc92cc0842c0dc72017751d 100644 (file)
@@ -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);
        }
 }