Merge branch 'tr/maint-1.6.3-add-p-modeonly-fix' into maint-1.6.3
authorJunio C Hamano <gitster@pobox.com>
Wed, 26 Aug 2009 18:22:00 +0000 (11:22 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 26 Aug 2009 18:22:00 +0000 (11:22 -0700)
* tr/maint-1.6.3-add-p-modeonly-fix:
  add -p: do not attempt to coalesce mode changes
  git add -p: demonstrate failure when staging both mode and hunk

135 files changed:
.gitattributes
Documentation/RelNotes-1.6.3.2.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.3.3.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.3.4.txt [new file with mode: 0644]
Documentation/asciidoc.conf
Documentation/config.txt
Documentation/fetch-options.txt
Documentation/git-cat-file.txt
Documentation/git-ls-tree.txt
Documentation/git-merge.txt
Documentation/git-remote.txt
Documentation/git-rerere.txt
Documentation/git-rev-list.txt
Documentation/git-send-email.txt
Documentation/git-show-ref.txt
Documentation/git-stash.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-symbolic-ref.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcore-tutorial.txt
Documentation/gittutorial.txt
Documentation/merge-options.txt
Documentation/technical/api-parse-options.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
alias.c
attr.c
base85.c
builtin-add.c
builtin-apply.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-checkout.c
builtin-clone.c
builtin-commit.c
builtin-fast-export.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-log.c
builtin-merge.c
builtin-pack-objects.c
builtin-prune-packed.c
builtin-prune.c
builtin-receive-pack.c
builtin-reflog.c
builtin-remote.c
builtin-rerere.c
builtin-send-pack.c
builtin-show-branch.c
builtin-tag.c
builtin-unpack-objects.c
builtin-upload-archive.c
builtin-verify-pack.c
builtin-verify-tag.c
combine-diff.c
config.c
configure.ac
connect.c
contrib/completion/git-completion.bash
contrib/fast-import/import-tars.perl
contrib/hg-to-git/hg-to-git.py
daemon.c
decorate.c
delta.h
diff-lib.c
diff.c
dir.c
entry.c
fast-import.c
git-add--interactive.perl
git-compat-util.h
git-pull.sh
git-rebase--interactive.sh
git-rebase.sh
git-request-pull.sh
git-send-email.perl
gitweb/README
grep.c
help.c
http-push.c
http-walker.c
http.c
index-pack.c
ll-merge.c
lockfile.c
merge-recursive.c
object.c
pack-refs.c
patch-delta.c
refs.c
remote.c
rerere.c
send-pack.h
server-info.c
sha1_file.c
sha1_name.c
strbuf.c
t/t1300-repo-config.sh
t/t3030-merge-recursive.sh
t/t3031-merge-criscross.sh [new file with mode: 0755]
t/t3505-cherry-pick-empty.sh
t/t3700-add.sh
t/t3701-add-interactive.sh
t/t4014-format-patch.sh
t/t4021-format-patch-numbered.sh
t/t4038-diff-combined.sh [new file with mode: 0755]
t/t4124-apply-ws-rule.sh
t/t4131-apply-fake-ancestor.sh [new file with mode: 0755]
t/t5000-tar-tree.sh
t/t5505-remote.sh
t/t5510-fetch.sh
t/t6023-merge-file.sh
t/t6200-fmt-merge-msg.sh
t/t7002-grep.sh
t/t7201-co.sh
t/t7500-commit.sh
t/t8003-blame.sh
t/t8005-blame-i18n.sh
t/t8005/euc-japan.txt [new file with mode: 0644]
t/t8005/sjis.txt
t/t8005/utf8.txt
templates/hooks--pre-commit.sample
transport.c
unpack-trees.c
userdiff.c
wrapper.c
ws.c
xdiff/xmerge.c

index 6b9c715..0636dee 100644 (file)
@@ -1,2 +1,2 @@
 * whitespace=!indent,trail,space
-*.[ch] whitespace
+*.[ch] whitespace=indent,trail,space
diff --git a/Documentation/RelNotes-1.6.3.2.txt b/Documentation/RelNotes-1.6.3.2.txt
new file mode 100644 (file)
index 0000000..b2f3f02
--- /dev/null
@@ -0,0 +1,61 @@
+GIT v1.6.3.2 Release Notes
+==========================
+
+Fixes since v1.6.3.1
+--------------------
+
+ * A few codepaths picked up the first few bytes from an sha1[] by
+   casting the (char *) pointer to (int *); GCC 4.4 did not like this,
+   and aborted compilation.
+
+ * Some unlink(2) failures went undiagnosed.
+
+ * The "recursive" merge strategy misbehaved when faced rename/delete
+   conflicts while coming up with an intermediate merge base.
+
+ * The low-level merge algorithm did not handle a degenerate case of
+   merging a file with itself using itself as the common ancestor
+   gracefully.  It should produce the file itself, but instead
+   produced an empty result.
+
+ * GIT_TRACE mechanism segfaulted when tracing a shell-quoted aliases.
+
+ * OpenBSD also uses st_ctimspec in "struct stat", instead of "st_ctim".
+
+ * With NO_CROSS_DIRECTORY_HARDLINKS, "make install" can be told not to
+   create hardlinks between $(gitexecdir)/git-$builtin_commands and
+   $(bindir)/git.
+
+ * command completion code in bash did not reliably detect that we are
+   in a bare repository.
+
+ * "git add ." in an empty directory complained that pathspec "." did not
+   match anything, which may be technically correct, but not useful.  We
+   silently make it a no-op now.
+
+ * "git add -p" (and "patch" action in "git add -i") was broken when
+   the first hunk that adds a line at the top was split into two and
+   both halves are marked to be used.
+
+ * "git blame path" misbehaved at the commit where path became file
+   from a directory with some files in it.
+
+ * "git for-each-ref" had a segfaulting bug when dealing with a tag object
+   created by an ancient git.
+
+ * "git format-patch -k" still added patch numbers if format.numbered
+   configuration was set.
+
+ * "git grep --color ''" did not terminate.  The command also had
+   subtle bugs with its -w option.
+
+ * http-push had a small use-after-free bug.
+
+ * "git push" was converting OFS_DELTA pack representation into less
+   efficient REF_DELTA representation unconditionally upon transfer,
+   making the transferred data unnecessarily larger.
+
+ * "git remote show origin" segfaulted when origin was still empty.
+
+Many other general usability updates around help text, diagnostic messages
+and documentation are included as well.
diff --git a/Documentation/RelNotes-1.6.3.3.txt b/Documentation/RelNotes-1.6.3.3.txt
new file mode 100644 (file)
index 0000000..1c28398
--- /dev/null
@@ -0,0 +1,38 @@
+GIT v1.6.3.3 Release Notes
+==========================
+
+Fixes since v1.6.3.2
+--------------------
+
+ * "git archive" running on Cygwin can get stuck in an infinite loop.
+
+ * "git daemon" did not correctly parse the initial line that carries
+   virtual host request information.
+
+ * "git diff --textconv" leaked memory badly when the textconv filter
+   errored out.
+
+ * The built-in regular expressions to pick function names to put on
+   hunk header lines for java and objc were very inefficiently written.
+
+ * in certain error situations git-fetch (and git-clone) on Windows didn't
+   detect connection abort and ended up waiting indefinitely.
+
+ * import-tars script (in contrib) did not import symbolic links correctly.
+
+ * http.c used CURLOPT_SSLKEY even on libcURL version 7.9.2, even though
+   it was only available starting 7.9.3.
+
+ * low-level filelevel merge driver used return value from strdup()
+   without checking if we ran out of memory.
+
+ * "git rebase -i" left stray closing parenthesis in its reflog message.
+
+ * "git remote show" did not show all the URLs associated with the named
+   remote, even though "git remote -v" did.  Made them consistent by
+   making the former show all URLs.
+
+ * "whitespace" attribute that is set was meant to detect all errors known
+   to git, but it told git to ignore trailing carriage-returns.
+
+Includes other documentation fixes.
diff --git a/Documentation/RelNotes-1.6.3.4.txt b/Documentation/RelNotes-1.6.3.4.txt
new file mode 100644 (file)
index 0000000..cad461b
--- /dev/null
@@ -0,0 +1,36 @@
+GIT v1.6.3.4 Release Notes
+==========================
+
+Fixes since v1.6.3.3
+--------------------
+
+ * "git add --no-ignore-errors" did not override configured
+   add.ignore-errors configuration.
+
+ * "git apply --whitespace=fix" did not fix trailing whitespace on an
+   incomplete line.
+
+ * "git branch" opened too many commit objects unnecessarily.
+
+ * "git checkout -f $commit" with a path that is a file (or a symlink) in
+   the work tree to a commit that has a directory at the path issued an
+   unnecessary error message.
+
+ * "git diff -c/--cc" was very inefficient in coalescing the removed lines
+   shared between parents.
+
+ * "git diff -c/--cc" showed removed lines at the beginning of a file
+   incorrectly.
+
+ * "git remote show nickname" did not honor configured
+   remote.nickname.uploadpack when inspecting the branches at the remote.
+
+ * "git request-pull" when talking to the terminal for a preview
+   showed some of the output in the pager.
+
+ * "git request-pull start nickname [end]" did not honor configured
+   remote.nickname.uploadpack when it ran git-ls-remote against the remote
+   repository to learn the current tip of branches.
+
+Includes other documentation updates and minor fixes.
+
index dc76e7f..87a90f2 100644 (file)
@@ -17,6 +17,7 @@ caret=&#94;
 startsb=&#91;
 endsb=&#93;
 tilde=&#126;
+backtick=&#96;
 
 ifdef::backend-docbook[]
 [linkgit-inlinemacro]
index 5dcad94..181c2f9 100644 (file)
@@ -438,6 +438,11 @@ On some file system/operating system combinations, this is unreliable.
 Set this config setting to 'rename' there; However, This will remove the
 check that makes sure that existing object files will not get overwritten.
 
+add.ignore-errors::
+       Tells 'git-add' to continue adding files when some files cannot be
+       added due to indexing errors. Equivalent to the '--ignore-errors'
+       option of linkgit:git-add[1].
+
 alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
        after defining "alias.last = cat-file commit HEAD", the invocation
@@ -451,7 +456,9 @@ If the alias expansion is prefixed with an exclamation point,
 it will be treated as a shell command.  For example, defining
 "alias.new = !gitk --all --not ORIG_HEAD", the invocation
 "git new" is equivalent to running the shell command
-"gitk --all --not ORIG_HEAD".
+"gitk --all --not ORIG_HEAD".  Note that shell commands will be
+executed from the top-level directory of a repository, which may
+not necessarily be the current directory.
 
 apply.whitespace::
        Tells 'git-apply' how to handle whitespaces, in the same way
@@ -597,7 +604,7 @@ color.interactive.<slot>::
        Use customized color for 'git-add --interactive'
        output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
        four distinct types of normal output from interactive
-       programs.  The values of these variables may be specified as
+       commands.  The values of these variables may be specified as
        in color.branch.<slot>.
 
 color.pager::
@@ -1093,7 +1100,7 @@ instaweb.port::
        linkgit:git-instaweb[1].
 
 interactive.singlekey::
-       In interactive programs, allow the user to provide one-letter
+       In interactive commands, allow the user to provide one-letter
        input with a single key (i.e., without hitting enter).
        Currently this is used only by the `\--patch` mode of
        linkgit:git-add[1].  Note that this setting is silently
index d313795..ea3b1bc 100644 (file)
@@ -1,7 +1,7 @@
 -q::
 --quiet::
        Pass --quiet to git-fetch-pack and silence any other internally
-       used programs.
+       used git commands.
 
 -v::
 --verbose::
index b191276..58c8d65 100644 (file)
@@ -9,8 +9,8 @@ git-cat-file - Provide content or type and size information for repository objec
 SYNOPSIS
 --------
 [verse]
-'git cat-file' [-t | -s | -e | -p | <type>] <object>
-'git cat-file' [--batch | --batch-check] < <list-of-objects>
+'git cat-file' (-t | -s | -e | -p | <type>) <object>
+'git cat-file' (--batch | --batch-check) < <list-of-objects>
 
 DESCRIPTION
 -----------
index f68e5c5..c3fdccb 100644 (file)
@@ -82,8 +82,10 @@ Output Format
 -------------
         <mode> SP <type> SP <object> TAB <file>
 
-When the `-z` option is not used, TAB, LF, and backslash characters
+Unless the `-z` option is used, TAB, LF, and backslash characters
 in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
+This output format is compatible with what '--index-info --stdin' of
+'git update-index' expects.
 
 When the `-l` option is used, format changes to
 
index c04ae73..af68d69 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
-       [-m <msg>] <remote> <remote>...
+       [-m <msg>] <remote>...
 'git merge' <msg> HEAD <remote>...
 
 DESCRIPTION
index 9e2b4ea..82a3d29 100644 (file)
@@ -114,14 +114,14 @@ These stale branches have already been removed from the remote repository
 referenced by <name>, but are still locally available in
 "remotes/<name>".
 +
-With `--dry-run` option, report what branches will be pruned, but do no
+With `--dry-run` option, report what branches will be pruned, but do not
 actually prune them.
 
 'update'::
 
 Fetch updates for a named set of remotes in the repository as defined by
 remotes.<group>.  If a named group is not specified on the command line,
-the configuration parameter remotes.default will get used; if
+the configuration parameter remotes.default will be used; if
 remotes.default is not defined, all remotes which do not have the
 configuration parameter remote.<name>.skipDefaultUpdate set to true will
 be updated.  (See linkgit:git-config[1]).
index 64715c1..a53c3cd 100644 (file)
@@ -12,15 +12,15 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-In a workflow that employs relatively long lived topic branches,
-the developer sometimes needs to resolve the same conflict over
+In a workflow employing relatively long lived topic branches,
+the developer sometimes needs to resolve the same conflicts over
 and over again until the topic branches are done (either merged
 to the "release" branch, or sent out and accepted upstream).
 
-This command helps this process by recording conflicted
-automerge results and corresponding hand-resolve results on the
-initial manual merge, and later by noticing the same automerge
-results and applying the previously recorded hand resolution.
+This command assists the developer in this process by recording
+conflicted automerge results and corresponding hand resolve results
+on the initial manual merge, and applying previously recorded
+hand resolutions to their corresponding automerge results.
 
 [NOTE]
 You need to set the configuration variable rerere.enabled to
@@ -54,18 +54,18 @@ for resolutions.
 
 'gc'::
 
-This command is used to prune records of conflicted merge that
-occurred long time ago.  By default, conflicts older than 15
-days that you have not recorded their resolution, and conflicts
-older than 60 days, are pruned.  These are controlled with
+This prunes records of conflicted merges that
+occurred a long time ago.  By default, unresolved conflicts older
+than 15 days and resolved conflicts older than 60
+days are pruned.  These defaults are controlled via the
 `gc.rerereunresolved` and `gc.rerereresolved` configuration
-variables.
+variables respectively.
 
 
 DISCUSSION
 ----------
 
-When your topic branch modifies overlapping area that your
+When your topic branch modifies an overlapping area that your
 master branch (or upstream) touched since your topic branch
 forked from it, you may want to test it with the latest master,
 even before your topic branch is ready to be pushed upstream:
@@ -140,9 +140,9 @@ top of the tip before the test merge:
 This would leave only one merge commit when your topic branch is
 finally ready and merged into the master branch.  This merge
 would require you to resolve the conflict, introduced by the
-commits marked with `*`.  However, often this conflict is the
+commits marked with `*`.  However, this conflict is often the
 same conflict you resolved when you created the test merge you
-blew away.  'git-rerere' command helps you to resolve this final
+blew away.  'git-rerere' helps you resolve this final
 conflicted merge using the information from your earlier hand
 resolve.
 
@@ -150,33 +150,32 @@ Running the 'git-rerere' command immediately after a conflicted
 automerge records the conflicted working tree files, with the
 usual conflict markers `<<<<<<<`, `=======`, and `>>>>>>>` in
 them.  Later, after you are done resolving the conflicts,
-running 'git-rerere' again records the resolved state of these
+running 'git-rerere' again will record the resolved state of these
 files.  Suppose you did this when you created the test merge of
 master into the topic branch.
 
-Next time, running 'git-rerere' after seeing a conflicted
-automerge, if the conflict is the same as the earlier one
-recorded, it is noticed and a three-way merge between the
+Next time, after seeing the same conflicted automerge,
+running 'git-rerere' will perform a three-way merge between the
 earlier conflicted automerge, the earlier manual resolution, and
-the current conflicted automerge is performed by the command.
+the current conflicted automerge.
 If this three-way merge resolves cleanly, the result is written
-out to your working tree file, so you would not have to manually
+out to your working tree file, so you do not have to manually
 resolve it.  Note that 'git-rerere' leaves the index file alone,
 so you still need to do the final sanity checks with `git diff`
 (or `git diff -c`) and 'git-add' when you are satisfied.
 
 As a convenience measure, 'git-merge' automatically invokes
-'git-rerere' when it exits with a failed automerge, which
-records it if it is a new conflict, or reuses the earlier hand
+'git-rerere' upon exiting with a failed automerge and 'git-rerere'
+records the hand resolve when it is a new conflict, or reuses the earlier hand
 resolve when it is not.  'git-commit' also invokes 'git-rerere'
-when recording a merge result.  What this means is that you do
-not have to do anything special yourself (Note: you still have
-to set the config variable rerere.enabled to enable this command).
+when committing a merge result.  What this means is that you do
+not have to do anything special yourself (besides enabling
+the rerere.enabled config variable).
 
-In our example, when you did the test merge, the manual
+In our example, when you do the test merge, the manual
 resolution is recorded, and it will be reused when you do the
-actual merge later with updated master and topic branch, as long
-as the earlier resolution is still applicable.
+actual merge later with the updated master and topic branch, as long
+as the recorded resolution is still applicable.
 
 The information 'git-rerere' records is also used when running
 'git-rebase'.  After blowing away the test merge and continuing
@@ -194,11 +193,11 @@ development on the topic branch:
     o---o---o---*---o---o---o---o   master
 ------------
 
-you could run `git rebase master topic`, to keep yourself
-up-to-date even before your topic is ready to be sent upstream.
-This would result in falling back to three-way merge, and it
-would conflict the same way the test merge you resolved earlier.
-'git-rerere' is run by 'git-rebase' to help you resolve this
+you could run `git rebase master topic`, to bring yourself
+up-to-date before your topic is ready to be sent upstream.
+This would result in falling back to three-way merge, and it
+would conflict the same way as the test merge you resolved earlier.
+'git-rerere' will be run by 'git-rebase' to help you resolve this
 conflict.
 
 
index 1c9cc28..ae1186e 100644 (file)
@@ -83,7 +83,7 @@ between the two operands.  The following two commands are equivalent:
        $ git rev-list A...B
 -----------------------------------------------------------------------
 
-'git-rev-list' is a very essential git program, since it
+'rev-list' is a very essential git command, since it
 provides the ability to build and traverse commit ancestry graphs. For
 this reason, it has a lot of different options that enables it to be
 used by commands as different as 'git-bisect' and
index 794224b..a282190 100644 (file)
@@ -14,6 +14,10 @@ SYNOPSIS
 DESCRIPTION
 -----------
 Takes the patches given on the command line and emails them out.
+Patches can be specified as files, directories (which will send all
+files in the directory), or directly as a revision list.  In the
+last case, any format accepted by linkgit:git-format-patch[1] can
+be passed to git send-email.
 
 The header of the email is configurable by command line options.  If not
 specified on the command line, the user will be prompted with a ReadLine
index 2f173ff..98e294a 100644 (file)
@@ -24,7 +24,7 @@ The --exclude-existing form is a filter that does the inverse, it shows the
 refs from stdin that don't exist in the local repository.
 
 Use of this utility is encouraged in favor of directly accessing files under
-in the `.git` directory.
+the `.git` directory.
 
 OPTIONS
 -------
@@ -50,7 +50,7 @@ OPTIONS
 -s::
 --hash::
 
-       Only show the SHA1 hash, not the reference name. When also using
+       Only show the SHA1 hash, not the reference name. When combined with
        --dereference the dereferenced tag will still be shown after the SHA1.
 
 --verify::
index 051f94d..1cc24cc 100644 (file)
@@ -75,14 +75,22 @@ show [<stash>]::
        it will accept any format known to 'git-diff' (e.g., `git stash show
        -p stash@\{1}` to view the second most recent stash in patch form).
 
-apply [--index] [<stash>]::
+pop [<stash>]::
 
-       Restore the changes recorded in the stash on top of the current
-       working tree state.  When no `<stash>` is given, applies the latest
-       one.  The working directory must match the index.
+       Remove a single stashed state from the stash list and apply it
+       on top of the current working tree state, i.e., do the inverse
+       operation of `git stash save`. The working directory must
+       match the index.
 +
-This operation can fail with conflicts; you need to resolve them
-by hand in the working tree.
+Applying the state can fail with conflicts; in this case, it is not
+removed from the stash list. You need to resolve the conflicts by hand
+and call `git stash drop` manually afterwards.
++
+When no `<stash>` is given, `stash@\{0}` is assumed. See also `apply`.
+
+apply [--index] [<stash>]::
+
+       Like `pop`, but do not remove the state from the stash list.
 +
 If the `--index` option is used, then tries to reinstate not only the working
 tree's changes, but also the index's ones. However, this can fail, when you
@@ -112,12 +120,6 @@ drop [<stash>]::
        Remove a single stashed state from the stash list. When no `<stash>`
        is given, it removes the latest one. i.e. `stash@\{0}`
 
-pop [<stash>]::
-
-       Remove a single stashed state from the stash list and apply on top
-       of the current working tree state. When no `<stash>` is given,
-       `stash@\{0}` is assumed. See also `apply`.
-
 create::
 
        Create a stash (which is a regular commit object) and return its
@@ -163,7 +165,7 @@ $ git pull
 file foobar not up to date, cannot merge.
 $ git stash
 $ git pull
-$ git stash apply
+$ git stash pop
 ----------------------------------------------------------------
 
 Interrupted workflow::
@@ -192,7 +194,7 @@ You can use 'git-stash' to simplify the above, like this:
 $ git stash
 $ edit emergency fix
 $ git commit -a -m "Fix in a hurry"
-$ git stash apply
+$ git stash pop
 # ... continue hacking ...
 ----------------------------------------------------------------
 
index 3b8df44..15b34d3 100644 (file)
@@ -137,8 +137,9 @@ foreach::
        the processing to terminate. This can be overridden by adding '|| :'
        to the end of the command.
 +
-As an example, "git submodule foreach 'echo $path `git rev-parse HEAD`' will
-show the path and currently checked out commit for each submodule.
+As an example, +git submodule foreach \'echo $path {backtick}git
+rev-parse HEAD{backtick}'+ will show the path and currently checked out
+commit for each submodule.
 
 sync::
        Synchronizes submodules' remote URL configuration setting
index 1c40894..74be843 100644 (file)
@@ -615,7 +615,7 @@ pulled or merged from.  This is because the author favored
 If you use `git svn set-tree A..B` to commit several diffs and you do
 not have the latest remotes/git-svn merged into my-branch, you should
 use `git svn rebase` to update your work branch instead of `git pull` or
-`git merge`.  `pull`/`merge' can cause non-linear history to be flattened
+`git merge`.  `pull`/`merge` can cause non-linear history to be flattened
 when committing into SVN, which can lead to merge commits reversing
 previous commits in SVN.
 
index 210fde0..6392538 100644 (file)
@@ -14,9 +14,9 @@ DESCRIPTION
 Given one argument, reads which branch head the given symbolic
 ref refers to and outputs its path, relative to the `.git/`
 directory.  Typically you would give `HEAD` as the <name>
-argument to see on which branch your working tree is on.
+argument to see which branch your working tree is on.
 
-Give two arguments, create or update a symbolic ref <name> to
+Given two arguments, creates or updates a symbolic ref <name> to
 point at the given branch <ref>.
 
 A symbolic ref is a regular file that stores a string that
index 9d8f236..8fbe187 100644 (file)
@@ -227,6 +227,8 @@ The link:user-manual.html#git-concepts[git concepts chapter of the
 user-manual] and linkgit:gitcore-tutorial[7] both provide
 introductions to the underlying git architecture.
 
+See linkgit:gitworkflows[7] for an overview of recommended workflows.
+
 See also the link:howto-index.html[howto] documents for some useful
 examples.
 
@@ -313,7 +315,7 @@ Synching repositories
 
 include::cmds-synchingrepositories.txt[]
 
-The following are helper programs used by the above; end users
+The following are helper commands used by the above; end users
 typically do not use them directly.
 
 include::cmds-synchelpers.txt[]
@@ -644,7 +646,8 @@ SEE ALSO
 linkgit:gittutorial[7], linkgit:gittutorial-2[7],
 link:everyday.html[Everyday Git], linkgit:gitcvs-migration[7],
 linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
-linkgit:gitcli[7], link:user-manual.html[The Git User's Manual]
+linkgit:gitcli[7], link:user-manual.html[The Git User's Manual],
+linkgit:gitworkflows[7]
 
 GIT
 ---
index aaa073e..1195e83 100644 (file)
@@ -404,7 +404,7 @@ Performing a three-way merge
 
 The attribute `merge` affects how three versions of a file is
 merged when a file-level merge is necessary during `git merge`,
-and other programs such as `git revert` and `git cherry-pick`.
+and other commands such as `git revert` and `git cherry-pick`.
 
 Set::
 
index 7ba5e58..b3640c4 100644 (file)
@@ -12,7 +12,7 @@ git *
 DESCRIPTION
 -----------
 
-This tutorial explains how to use the "core" git programs to set up and
+This tutorial explains how to use the "core" git commands to set up and
 work with a git repository.
 
 If you just need to use git as a revision control system you may prefer
@@ -1328,7 +1328,7 @@ into it later. Obviously, this repository creation needs to be
 done only once.
 
 [NOTE]
-'git-push' uses a pair of programs,
+'git-push' uses a pair of commands,
 'git-send-pack' on your local machine, and 'git-receive-pack'
 on the remote machine. The communication between the two over
 the network internally uses an SSH connection.
index c5d5596..cf0689c 100644 (file)
@@ -332,11 +332,11 @@ alice$ git log -p HEAD..FETCH_HEAD
 ------------------------------------------------
 
 This operation is safe even if Alice has uncommitted local changes.
-The range notation HEAD..FETCH_HEAD" means "show everything that is reachable
-from the FETCH_HEAD but exclude anything that is reachable from HEAD.
+The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
+from the FETCH_HEAD but exclude anything that is reachable from HEAD".
 Alice already knows everything that leads to her current state (HEAD),
-and reviewing what Bob has in his state (FETCH_HEAD) that she has not
-seen with this command
+and reviews what Bob has in his state (FETCH_HEAD) that she has not
+seen with this command.
 
 If Alice wants to visualize what Bob did since their histories forked
 she can issue the following command:
@@ -375,9 +375,9 @@ it easier:
 alice$ git remote add bob /home/bob/myrepo
 ------------------------------------------------
 
-With this, Alice can perform the first part of the "pull" operation alone using the
-'git-fetch' command without merging them with her own branch,
-using:
+With this, Alice can perform the first part of the "pull" operation
+alone using the 'git-fetch' command without merging them with her own
+branch, using:
 
 -------------------------------------
 alice$ git fetch bob
@@ -566,22 +566,22 @@ $ git log v2.5.. Makefile       # commits since v2.5 which modify
 
 You can also give 'git-log' a "range" of commits where the first is not
 necessarily an ancestor of the second; for example, if the tips of
-the branches "stable-release" and "master" diverged from a common
+the branches "stable" and "master" diverged from a common
 commit some time ago, then
 
 -------------------------------------
-$ git log stable..experimental
+$ git log stable..master
 -------------------------------------
 
-will list commits made in the experimental branch but not in the
+will list commits made in the master branch but not in the
 stable branch, while
 
 -------------------------------------
-$ git log experimental..stable
+$ git log master..stable
 -------------------------------------
 
 will show the list of commits made on the stable branch but not
-the experimental branch.
+the master branch.
 
 The 'git-log' command has a weakness: it must present commits in a
 list.  When the history has lines of development that diverged and
@@ -650,6 +650,9 @@ digressions that may be interesting at this point are:
     smart enough to perform a close-to-optimal search even in the
     case of complex non-linear history with lots of merged branches.
 
+  * linkgit:gitworkflows[7]: Gives an overview of recommended
+    workflows.
+
   * link:everyday.html[Everyday GIT with 20 Commands Or So]
 
   * linkgit:gitcvs-migration[7]: Git for CVS users.
@@ -661,6 +664,7 @@ linkgit:gitcvs-migration[7],
 linkgit:gitcore-tutorial[7],
 linkgit:gitglossary[7],
 linkgit:git-help[1],
+linkgit:gitworkflows[7],
 link:everyday.html[Everyday git],
 link:user-manual.html[The Git User's Manual]
 
index 637b53f..adadf8e 100644 (file)
@@ -39,7 +39,8 @@
 
 --squash::
        Produce the working tree and index state as if a real
-       merge happened, but do not actually make a commit or
+       merge happened (except for the merge information),
+       but do not actually make a commit or
        move the `HEAD`, nor record `$GIT_DIR/MERGE_HEAD` to
        cause the next `git commit` command to create a merge
        commit.  This allows you to create a single commit on
index e66ca9f..e30c602 100644 (file)
@@ -198,7 +198,7 @@ The function must be defined in this form:
 
 The callback mechanism is as follows:
 
-* Inside `funct`, the only interesting member of the structure
+* Inside `func`, 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()`.
index dbbeb7e..67ebffa 100644 (file)
@@ -1520,10 +1520,10 @@ $ git commit -a -m "blorpl: typofix"
 ------------------------------------------------
 
 After that, you can go back to what you were working on with
-`git stash apply`:
+`git stash pop`:
 
 ------------------------------------------------
-$ git stash apply
+$ git stash pop
 ------------------------------------------------
 
 
@@ -4131,7 +4131,7 @@ What does this mean?
 
 `git rev-list` is the original version of the revision walker, which
 _always_ printed a list of revisions to stdout.  It is still functional,
-and needs to, since most new Git programs start out as scripts using
+and needs to, since most new Git commands start out as scripts using
 `git rev-list`.
 
 `git rev-parse` is not as important any more; it was only used to filter out
index d292e3a..a56dcb2 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.6.3.1
+DEF_VER=v1.6.3.4
 
 LF='
 '
index 6e21643..f88ed3e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -175,6 +175,9 @@ all::
 # Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems
 # when hardlinking a file to another name and unlinking the original file right
 # away (some NTFS drivers seem to zero the contents in that scenario).
+#
+# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
+# programs as a tar, where bin/ and libexec/ might be on different file systems.
 
 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -699,6 +702,7 @@ ifeq ($(uname_S),SunOS)
        NO_HSTRERROR = YesPlease
        NO_MKDTEMP = YesPlease
        OLD_ICONV = UnfortunatelyYes
+       NO_EXTERNAL_GREP = YesPlease
        ifeq ($(uname_R),5.8)
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
@@ -749,6 +753,7 @@ endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
+       USE_ST_TIMESPEC = YesPlease
        NEEDS_LIBICONV = YesPlease
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
@@ -1381,7 +1386,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
+$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
 builtin-revert.o wt-status.o: wt-status.h
 
 $(LIB_FILE): $(LIB_OBJS)
@@ -1549,6 +1554,7 @@ endif
        bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
        execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
        { $(RM) "$$execdir/git-add$X" && \
+               test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
                ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
                cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
        { for p in $(filter-out git-add$X,$(BUILT_INS)); do \
index 0f6a588..03c996d 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.6.3.1.txt
\ No newline at end of file
+Documentation/RelNotes-1.6.3.4.txt
\ No newline at end of file
diff --git a/alias.c b/alias.c
index e687fe5..372b7d8 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
                        while (cmdline[++src]
                                        && isspace(cmdline[src]))
                                ; /* skip */
-                       if (count >= size) {
-                               size += 16;
-                               *argv = xrealloc(*argv, sizeof(char *) * size);
-                       }
+                       ALLOC_GROW(*argv, count+1, size);
                        (*argv)[count++] = cmdline + dst;
                } else if (!quoted && (c == '\'' || c == '"')) {
                        quoted = c;
@@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
                return error("unclosed quote");
        }
 
+       ALLOC_GROW(*argv, count+1, size);
+       (*argv)[count] = NULL;
+
        return count;
 }
 
diff --git a/attr.c b/attr.c
index 98eb636..55bdb7c 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -35,8 +35,7 @@ static struct git_attr *(git_attr_hash[HASHSIZE]);
 
 static unsigned hash_name(const char *name, int namelen)
 {
-       unsigned val = 0;
-       unsigned char c;
+       unsigned val = 0, c;
 
        while (namelen--) {
                c = *name++;
@@ -556,6 +555,8 @@ static void prepare_attr_stack(const char *path, int dirlen)
                }
        }
 
+       strbuf_release(&pathbuf);
+
        /*
         * Finally push the "info" one at the top of the stack.
         */
index b88270f..b417a15 100644 (file)
--- a/base85.c
+++ b/base85.c
@@ -91,7 +91,7 @@ void encode_85(char *buf, const unsigned char *data, int bytes)
                unsigned acc = 0;
                int cnt;
                for (cnt = 24; cnt >= 0; cnt -= 8) {
-                       int ch = *data++;
+                       unsigned ch = *data++;
                        acc |= ch << cnt;
                        if (--bytes == 0)
                                break;
index cb67d2c..d6ad57b 100644 (file)
@@ -61,7 +61,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
        fill_pathspec_matches(pathspec, seen, specs);
 
        for (i = 0; i < specs; i++) {
-               if (!seen[i] && !file_exists(pathspec[i]))
+               if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
                        die("pathspec '%s' did not match any files",
                                        pathspec[i]);
        }
@@ -250,6 +250,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        int add_new_files;
        int require_pathspec;
 
+       git_config(add_config, NULL);
+
        argc = parse_options(argc, argv, builtin_add_options,
                          builtin_add_usage, 0);
        if (patch_interactive)
@@ -257,8 +259,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (add_interactive)
                exit(interactive_add(argc, argv, prefix));
 
-       git_config(add_config, NULL);
-
        if (addremove && take_worktree_changes)
                die("-A and -u are mutually incompatible");
        if ((addremove || take_worktree_changes) && !argc) {
index 7b404ef..a40b982 100644 (file)
@@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
                        if (rmdir(patch->old_name))
                                warning("unable to remove submodule %s",
                                        patch->old_name);
-               } else if (!unlink(patch->old_name) && rmdir_empty) {
+               } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
                        remove_path(patch->old_name);
                }
        }
@@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
                        if (!try_create_file(newpath, mode, buf, size)) {
                                if (!rename(newpath, path))
                                        return;
-                               unlink(newpath);
+                               unlink_or_warn(newpath);
                                break;
                        }
                        if (errno != EEXIST)
@@ -3315,6 +3315,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 
        argc = parse_options(argc, argv, builtin_apply_options,
                        apply_usage, 0);
+       fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor);
+       if (fake_ancestor)
+               fake_ancestor = xstrdup(fake_ancestor);
+
        if (apply_with_reject)
                apply = apply_verbosely = 1;
        if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
index cf74a92..0afdb16 100644 (file)
@@ -362,18 +362,28 @@ static struct origin *find_origin(struct scoreboard *sb,
                               "", &diff_opts);
        diffcore_std(&diff_opts);
 
-       /* It is either one entry that says "modified", or "created",
-        * or nothing.
-        */
        if (!diff_queued_diff.nr) {
                /* The path is the same as parent */
                porigin = get_origin(sb, parent, origin->path);
                hashcpy(porigin->blob_sha1, origin->blob_sha1);
-       }
-       else if (diff_queued_diff.nr != 1)
-               die("internal error in blame::find_origin");
-       else {
-               struct diff_filepair *p = diff_queued_diff.queue[0];
+       } else {
+               /*
+                * Since origin->path is a pathspec, if the parent
+                * commit had it as a directory, we will see a whole
+                * bunch of deletion of files in the directory that we
+                * do not care about.
+                */
+               int i;
+               struct diff_filepair *p = NULL;
+               for (i = 0; i < diff_queued_diff.nr; i++) {
+                       const char *name;
+                       p = diff_queued_diff.queue[i];
+                       name = p->one->path ? p->one->path : p->two->path;
+                       if (!strcmp(name, origin->path))
+                               break;
+               }
+               if (!p)
+                       die("internal error in blame::find_origin");
                switch (p->status) {
                default:
                        die("internal error in blame::find_origin (%c)",
index 91098ca..887fa60 100644 (file)
@@ -191,7 +191,7 @@ struct ref_item {
 
 struct ref_list {
        struct rev_info revs;
-       int index, alloc, maxwidth;
+       int index, alloc, maxwidth, verbose, abbrev;
        struct ref_item *list;
        struct commit_list *with_commit;
        int kinds;
@@ -240,21 +240,24 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        if (ARRAY_SIZE(ref_kind) <= i)
                return 0;
 
-       commit = lookup_commit_reference_gently(sha1, 1);
-       if (!commit)
-               return error("branch '%s' does not point at a commit", refname);
-
-       /* Filter with with_commit if specified */
-       if (!is_descendant_of(commit, ref_list->with_commit))
-               return 0;
-
        /* Don't add types the caller doesn't want */
        if ((kind & ref_list->kinds) == 0)
                return 0;
 
-       if (merge_filter != NO_FILTER)
-               add_pending_object(&ref_list->revs,
-                                  (struct object *)commit, refname);
+       commit = NULL;
+       if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
+               commit = lookup_commit_reference_gently(sha1, 1);
+               if (!commit)
+                       return error("branch '%s' does not point at a commit", refname);
+
+               /* Filter with with_commit if specified */
+               if (!is_descendant_of(commit, ref_list->with_commit))
+                       return 0;
+
+               if (merge_filter != NO_FILTER)
+                       add_pending_object(&ref_list->revs,
+                                          (struct object *)commit, refname);
+       }
 
        /* Resize buffer */
        if (ref_list->index >= ref_list->alloc) {
@@ -415,18 +418,38 @@ static int calc_maxwidth(struct ref_list *refs)
        return w;
 }
 
+
+static void show_detached(struct ref_list *ref_list)
+{
+       struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
+
+       if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
+               struct ref_item item;
+               item.name = xstrdup("(no branch)");
+               item.len = strlen(item.name);
+               item.kind = REF_LOCAL_BRANCH;
+               item.dest = NULL;
+               item.commit = head_commit;
+               if (item.len > ref_list->maxwidth)
+                       ref_list->maxwidth = item.len;
+               print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
+               free(item.name);
+       }
+}
+
 static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
 {
        int i;
        struct ref_list ref_list;
-       struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
 
        memset(&ref_list, 0, sizeof(ref_list));
        ref_list.kinds = kinds;
+       ref_list.verbose = verbose;
+       ref_list.abbrev = abbrev;
        ref_list.with_commit = with_commit;
        if (merge_filter != NO_FILTER)
                init_revisions(&ref_list.revs, NULL);
-       for_each_ref(append_ref, &ref_list);
+       for_each_rawref(append_ref, &ref_list);
        if (merge_filter != NO_FILTER) {
                struct commit *filter;
                filter = lookup_commit_reference_gently(merge_filter_ref, 0);
@@ -442,19 +465,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
        qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
 
        detached = (detached && (kinds & REF_LOCAL_BRANCH));
-       if (detached && head_commit &&
-           is_descendant_of(head_commit, with_commit)) {
-               struct ref_item item;
-               item.name = xstrdup("(no branch)");
-               item.len = strlen(item.name);
-               item.kind = REF_LOCAL_BRANCH;
-               item.dest = NULL;
-               item.commit = head_commit;
-               if (item.len > ref_list.maxwidth)
-                       ref_list.maxwidth = item.len;
-               print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, "");
-               free(item.name);
-       }
+       if (detached)
+               show_detached(&ref_list);
 
        for (i = 0; i < ref_list.index; i++) {
                int current = !detached &&
index 8fad19d..43ffe7f 100644 (file)
@@ -201,8 +201,8 @@ static int batch_objects(int print_contents)
 }
 
 static const char * const cat_file_usage[] = {
-       "git cat-file [-t|-s|-e|-p|<type>] <sha1>",
-       "git cat-file [--batch|--batch-check] < <list_of_sha1s>",
+       "git cat-file (-t|-s|-e|-p|<type>) <object>",
+       "git cat-file (--batch|--batch-check) < <list_of_objects>",
        NULL
 };
 
index dc4bfb5..b8a4b01 100644 (file)
@@ -216,7 +216,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 
        newfd = hold_locked_index(lock_file, 1);
-       if (read_cache() < 0)
+       if (read_cache_preload(pathspec) < 0)
                return error("corrupt index file");
 
        if (source_tree)
@@ -366,7 +366,7 @@ static int merge_working_tree(struct checkout_opts *opts,
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
        int newfd = hold_locked_index(lock_file, 1);
 
-       if (read_cache() < 0)
+       if (read_cache_preload(NULL) < 0)
                return error("corrupt index file");
 
        if (opts->force) {
@@ -541,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
                parse_commit(new->commit);
        }
 
-       /*
-        * If we were on a detached HEAD, but we are now moving to
-        * a new commit, we want to mention the old commit once more
-        * to remind the user that it might be lost.
-        */
-       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
-               describe_detached_head("Previous HEAD position was", old.commit);
-
        if (!old.commit && !opts->force) {
                if (!opts->quiet) {
                        warning("You appear to be on a branch yet to be born.");
@@ -561,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
        if (ret)
                return ret;
 
+       /*
+        * If we were on a detached HEAD, but have now moved to
+        * a new commit, we want to mention the old commit once more
+        * to remind the user that it might be lost.
+        */
+       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+               describe_detached_head("Previous HEAD position was", old.commit);
+
        update_refs_for_switch(opts, &old, new);
 
        ret = post_checkout_hook(old.commit, new->commit, 1);
index 880373f..ba286e0 100644 (file)
@@ -228,7 +228,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
                }
 
                if (unlink(dest->buf) && errno != ENOENT)
-                       die("failed to unlink %s", dest->buf);
+                       die("failed to unlink %s: %s",
+                           dest->buf, strerror(errno));
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
index 81371b1..baaa75c 100644 (file)
@@ -699,7 +699,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
 
        argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
        logfile = parse_options_fix_filename(prefix, logfile);
+       if (logfile)
+               logfile = xstrdup(logfile);
        template_file = parse_options_fix_filename(prefix, template_file);
+       if (template_file)
+               template_file = xstrdup(template_file);
 
        if (force_author && !strchr(force_author, '>'))
                force_author = find_author_by_nickname(force_author);
index 6731713..9091481 100644 (file)
@@ -428,21 +428,27 @@ static void export_marks(char *file)
        uint32_t mark;
        struct object_decoration *deco = idnums.hash;
        FILE *f;
+       int e = 0;
 
        f = fopen(file, "w");
        if (!f)
-               error("Unable to open marks file %s for writing", file);
+               error("Unable to open marks file %s for writing.", file);
 
        for (i = 0; i < idnums.size; i++) {
                if (deco->base && deco->base->type == 1) {
                        mark = ptr_to_mark(deco->decoration);
-                       fprintf(f, ":%"PRIu32" %s\n", mark,
-                               sha1_to_hex(deco->base->sha1));
+                       if (fprintf(f, ":%"PRIu32" %s\n", mark,
+                               sha1_to_hex(deco->base->sha1)) < 0) {
+                           e = 1;
+                           break;
+                       }
                }
                deco++;
        }
 
-       if (ferror(f) || fclose(f))
+       e |= ferror(f);
+       e |= fclose(f);
+       if (e)
                error("Unable to write marks file %s.", file);
 }
 
index 87f46c6..629735f 100644 (file)
@@ -483,7 +483,9 @@ static int sideband_demux(int fd, void *data)
 {
        int *xd = data;
 
-       return recv_sideband("fetch-pack", xd[0], fd);
+       int ret = recv_sideband("fetch-pack", xd[0], fd);
+       close(fd);
+       return ret;
 }
 
 static int get_pack(int xd[2], char **pack_lockfile)
@@ -825,7 +827,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                fd = hold_lock_file_for_update(&lock, shallow,
                                               LOCK_DIE_ON_ERROR);
                if (!write_shallow_commits(fd, 0)) {
-                       unlink(shallow);
+                       unlink_or_warn(shallow);
                        rollback_lock_file(&lock);
                } else {
                        commit_lock_file(&lock);
index 3c998ea..1f7a3f1 100644 (file)
@@ -167,6 +167,9 @@ static struct ref *get_ref_map(struct transport *transport,
        return ref_map;
 }
 
+#define STORE_REF_ERROR_OTHER 1
+#define STORE_REF_ERROR_DF_CONFLICT 2
+
 static int s_update_ref(const char *action,
                        struct ref *ref,
                        int check_old)
@@ -181,9 +184,11 @@ 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 2;
+               return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+                                         STORE_REF_ERROR_OTHER;
        if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
-               return 2;
+               return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+                                         STORE_REF_ERROR_OTHER;
        return 0;
 }
 
@@ -377,7 +382,7 @@ static int store_updated_refs(const char *url, const char *remote_name,
                }
        }
        fclose(fp);
-       if (rc & 2)
+       if (rc & STORE_REF_ERROR_DF_CONFLICT)
                error("some local refs could not be updated; try running\n"
                      " 'git remote prune %s' to remove any old, conflicting "
                      "branches", remote_name);
index a788369..fae1482 100644 (file)
@@ -363,6 +363,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
        if (argc > 0)
                usage_with_options(fmt_merge_msg_usage, options);
+       inpath = parse_options_fix_filename(prefix, inpath);
 
        if (inpath && strcmp(inpath, "-")) {
                in = fopen(inpath, "r");
index 91e8f95..1911cda 100644 (file)
@@ -339,8 +339,11 @@ static const char *copy_name(const char *buf)
 static const char *copy_email(const char *buf)
 {
        const char *email = strchr(buf, '<');
-       const char *eoemail = strchr(email, '>');
-       if (!email || !eoemail)
+       const char *eoemail;
+       if (!email)
+               return "";
+       eoemail = strchr(email, '>');
+       if (!eoemail)
                return "";
        return xmemdupz(email, eoemail + 1 - email);
 }
@@ -558,14 +561,6 @@ static void populate_value(struct refinfo *ref)
 
        ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
 
-       buf = get_obj(ref->objectname, &obj, &size, &eaten);
-       if (!buf)
-               die("missing object %s for %s",
-                   sha1_to_hex(ref->objectname), ref->refname);
-       if (!obj)
-               die("parse_object_buffer failed on %s for %s",
-                   sha1_to_hex(ref->objectname), ref->refname);
-
        /* Fill in specials first */
        for (i = 0; i < used_atom_cnt; i++) {
                const char *name = used_atom[i];
@@ -618,6 +613,22 @@ static void populate_value(struct refinfo *ref)
                }
        }
 
+       for (i = 0; i < used_atom_cnt; i++) {
+               struct atom_value *v = &ref->value[i];
+               if (v->s == NULL)
+                       goto need_obj;
+       }
+       return;
+
+ need_obj:
+       buf = get_obj(ref->objectname, &obj, &size, &eaten);
+       if (!buf)
+               die("missing object %s for %s",
+                   sha1_to_hex(ref->objectname), ref->refname);
+       if (!obj)
+               die("parse_object_buffer failed on %s for %s",
+                   sha1_to_hex(ref->objectname), ref->refname);
+
        grab_values(ref->value, 0, obj, buf, size);
        if (!eaten)
                free(buf);
@@ -923,7 +934,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 
        memset(&cbdata, 0, sizeof(cbdata));
        cbdata.grab_pattern = argv;
-       for_each_ref(grab_single_ref, &cbdata);
+       for_each_rawref(grab_single_ref, &cbdata);
        refs = cbdata.grab_array;
        num_refs = cbdata.grab_cnt;
 
index 5eaec5d..f10cfeb 100644 (file)
@@ -755,6 +755,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int cover_letter = 0;
        int boundary_count = 0;
        int no_binary_diff = 0;
+       int numbered_cmdline_opt = 0;
        struct commit *origin = NULL, *head = NULL;
        const char *in_reply_to = NULL;
        struct patch_ids ids;
@@ -786,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (!strcmp(argv[i], "--stdout"))
                        use_stdout = 1;
                else if (!strcmp(argv[i], "-n") ||
-                               !strcmp(argv[i], "--numbered"))
+                               !strcmp(argv[i], "--numbered")) {
                        numbered = 1;
+                       numbered_cmdline_opt = 1;
+               }
                else if (!strcmp(argv[i], "-N") ||
                                !strcmp(argv[i], "--no-numbered")) {
                        numbered = 0;
@@ -918,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        if (start_number < 0)
                start_number = 1;
+
+       /*
+        * If numbered is set solely due to format.numbered in config,
+        * and it would conflict with --keep-subject (-k) from the
+        * command line, reset "numbered".
+        */
+       if (numbered && keep_subject && !numbered_cmdline_opt)
+               numbered = 0;
+
        if (numbered && keep_subject)
                die ("-n and -k are mutually exclusive.");
        if (keep_subject && subject_prefix)
index 0b58e5e..9e9bd52 100644 (file)
@@ -836,8 +836,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        struct commit_list **remotes = &remoteheads;
 
        setup_work_tree();
+       if (file_exists(git_path("MERGE_HEAD")))
+               die("You have not concluded your merge. (MERGE_HEAD exists)");
        if (read_cache_unmerged())
-               die("You are in the middle of a conflicted merge.");
+               die("You are in the middle of a conflicted merge."
+                               " (index unmerged)");
 
        /*
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
index 9742b45..941cc2d 100644 (file)
@@ -653,8 +653,7 @@ static void rehash_objects(void)
 
 static unsigned name_hash(const char *name)
 {
-       unsigned char c;
-       unsigned hash = 0;
+       unsigned c, hash = 0;
 
        if (!name)
                return 0;
index 4942892..00590b1 100644 (file)
@@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
                memcpy(pathname + len, de->d_name, 38);
                if (opts & DRY_RUN)
                        printf("rm -f %s\n", pathname);
-               else if (unlink(pathname) < 0)
-                       error("unable to unlink %s", pathname);
+               else
+                       unlink_or_warn(pathname);
                display_progress(progress, i + 1);
        }
        pathname[len] = 0;
index 545e9c1..145ba83 100644 (file)
@@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename)
        }
        printf("Removing stale temporary file %s\n", fullpath);
        if (!show_only)
-               unlink(fullpath);
+               unlink_or_warn(fullpath);
        return 0;
 }
 
@@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
                       (type > 0) ? typename(type) : "unknown");
        }
        if (!show_only)
-               unlink(fullpath);
+               unlink_or_warn(fullpath);
        return 0;
 }
 
index a970b39..0b08da9 100644 (file)
@@ -27,10 +27,9 @@ static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
 static int report_status;
+static int prefer_ofs_delta = 1;
 static const char *head_name;
-
-static char capabilities[] = " report-status delete-refs ";
-static int capabilities_sent;
+static char *capabilities_to_send;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -84,24 +83,29 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
+               prefer_ofs_delta = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
-       if (capabilities_sent)
+       if (!capabilities_to_send)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
                packet_write(1, "%s %s%c%s\n",
-                            sha1_to_hex(sha1), path, 0, capabilities);
-       capabilities_sent = 1;
+                            sha1_to_hex(sha1), path, 0, capabilities_to_send);
+       capabilities_to_send = NULL;
        return 0;
 }
 
 static void write_head_info(void)
 {
        for_each_ref(show_ref, NULL);
-       if (!capabilities_sent)
+       if (capabilities_to_send)
                show_ref("capabilities^{}", null_sha1, 0, NULL);
 
 }
@@ -687,6 +691,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        else if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
 
+       capabilities_to_send = (prefer_ofs_delta) ?
+               " report-status delete-refs ofs-delta " :
+               " report-status delete-refs ";
+
        add_alternate_refs();
        write_head_info();
        clear_extra_refs();
@@ -702,7 +710,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        unpack_status = unpack();
                execute_commands(unpack_status);
                if (pack_lockfile)
-                       unlink(pack_lockfile);
+                       unlink_or_warn(pack_lockfile);
                if (report_status)
                        report(unpack_status);
                run_receive_hook(post_receive_hook);
index ddfdf5a..95198c5 100644 (file)
@@ -694,7 +694,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
  */
 
 static const char reflog_usage[] =
-"git reflog (expire | ...)";
+"git reflog [ show | expire | delete ]";
 
 int cmd_reflog(int argc, const char **argv, const char *prefix)
 {
index 2ed752c..7685cfc 100644 (file)
@@ -299,11 +299,11 @@ static int get_push_ref_states(const struct ref *remote_refs,
                return 0;
 
        local_refs = get_local_heads();
-       ref = push_map = copy_ref_list(remote_refs);
-       while (ref->next)
-               ref = ref->next;
-       push_tail = &ref->next;
+       push_map = copy_ref_list(remote_refs);
 
+       push_tail = &push_map;
+       while (*push_tail)
+               push_tail = &((*push_tail)->next);
        match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
                   remote->push_refspec, MATCH_REFS_NONE);
 
@@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote)
                path = git_path("remotes/%s", remote->name);
        else if (remote->origin == REMOTE_BRANCHES)
                path = git_path("branches/%s", remote->name);
-       if (path && unlink(path))
-               warning("failed to remove '%s'", path);
+       if (path)
+               unlink_or_warn(path);
        return 0;
 }
 
@@ -789,7 +789,7 @@ static int get_remote_ref_states(const char *name,
        read_branches();
 
        if (query) {
-               transport = transport_get(NULL, states->remote->url_nr > 0 ?
+               transport = transport_get(states->remote, states->remote->url_nr > 0 ?
                        states->remote->url[0] : NULL);
                remote_refs = transport_get_remote_refs(transport);
                transport_disconnect(transport);
@@ -1003,9 +1003,12 @@ static int show(int argc, const char **argv)
 
                get_remote_ref_states(*argv, &states, query_flag);
 
-               printf("* remote %s\n  URL: %s\n", *argv,
-                       states.remote->url_nr > 0 ?
-                               states.remote->url[0] : "(no URL)");
+               printf("* remote %s\n", *argv);
+               if (states.remote->url_nr) {
+                       for (i=0; i < states.remote->url_nr; i++)
+                               printf("  URL: %s\n", states.remote->url[i]);
+               } else
+                       printf("  URL: %s\n", "(no URL)");
                if (no_query)
                        printf("  HEAD branch: (not queried)\n");
                else if (!states.heads.nr)
index 020af73..adfb7b5 100644 (file)
@@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
                        if (!has_rerere_resolution(name))
                                unlink_rr_item(name);
                }
-               unlink(git_path("rr-cache/MERGE_RR"));
+               unlink_or_warn(git_path("rr-cache/MERGE_RR"));
        } else if (!strcmp(argv[1], "gc"))
                garbage_collect(&merge_rr);
        else if (!strcmp(argv[1], "status"))
index d5a1c48..473a3de 100644 (file)
@@ -43,12 +43,16 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
                "--stdout",
                NULL,
                NULL,
+               NULL,
        };
        struct child_process po;
        int i;
 
+       i = 4;
        if (args->use_thin_pack)
-               argv[4] = "--thin";
+               argv[i++] = "--thin";
+       if (args->use_ofs_delta)
+               argv[i++] = "--delta-base-offset";
        memset(&po, 0, sizeof(po));
        po.argv = argv;
        po.in = -1;
@@ -315,6 +319,8 @@ int send_pack(struct send_pack_args *args,
                ask_for_status_report = 1;
        if (server_supports("delete-refs"))
                allow_deleting_refs = 1;
+       if (server_supports("ofs-delta"))
+               args->use_ofs_delta = 1;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
index 828e6f8..c3afabb 100644 (file)
@@ -576,7 +576,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base)
        if (*ep == ',')
                *base = ep + 1;
        else if (*ep)
-               die("unrecognized reflog param '%s'", arg + 9);
+               die("unrecognized reflog param '%s'", arg);
        else
                *base = NULL;
        if (*cnt <= 0)
index 01e7374..e544430 100644 (file)
@@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag,
                exit(128);
        }
        if (path) {
-               unlink(path);
+               unlink_or_warn(path);
                free(path);
        }
 }
index 9a77323..8e831be 100644 (file)
@@ -422,8 +422,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
 static void unpack_one(unsigned nr)
 {
        unsigned shift;
-       unsigned char *pack, c;
-       unsigned long size;
+       unsigned char *pack;
+       unsigned long size, c;
        enum object_type type;
 
        obj_list[nr].offset = consumed_bytes;
index 0206b41..c4cd1e1 100644 (file)
@@ -80,16 +80,17 @@ static void error_clnt(const char *fmt, ...)
        die("sent error to the client: %s", buf);
 }
 
-static void process_input(int child_fd, int band)
+static ssize_t process_input(int child_fd, int band)
 {
        char buf[16384];
        ssize_t sz = read(child_fd, buf, sizeof(buf));
        if (sz < 0) {
                if (errno != EAGAIN && errno != EINTR)
                        error_clnt("read error: %s\n", strerror(errno));
-               return;
+               return sz;
        }
        send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
+       return sz;
 }
 
 int cmd_upload_archive(int argc, const char **argv, const char *prefix)
@@ -131,6 +132,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
 
        while (1) {
                struct pollfd pfd[2];
+               ssize_t processed[2] = { 0, 0 };
                int status;
 
                pfd[0].fd = fd1[0];
@@ -147,12 +149,12 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
                }
                if (pfd[0].revents & POLLIN)
                        /* Data stream ready */
-                       process_input(pfd[0].fd, 1);
+                       processed[0] = process_input(pfd[0].fd, 1);
                if (pfd[1].revents & POLLIN)
                        /* Status stream ready */
-                       process_input(pfd[1].fd, 2);
+                       processed[1] = process_input(pfd[1].fd, 2);
                /* Always finish to read data when available */
-               if ((pfd[0].revents | pfd[1].revents) & POLLIN)
+               if (processed[0] || processed[1])
                        continue;
 
                if (waitpid(writer, &status, 0) < 0)
index 0ee0a9a..a18df04 100644 (file)
@@ -7,10 +7,13 @@
 
 static void show_pack_info(struct packed_git *p)
 {
-       uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
+       uint32_t nr_objects, i;
+       int cnt;
+       unsigned long chain_histogram[MAX_CHAIN+1], baseobjects;
 
        nr_objects = p->num_objects;
        memset(chain_histogram, 0, sizeof(chain_histogram));
+       baseobjects = 0;
 
        for (i = 0; i < nr_objects; i++) {
                const unsigned char *sha1;
@@ -29,9 +32,11 @@ static void show_pack_info(struct packed_git *p)
                                                 &delta_chain_length,
                                                 base_sha1);
                printf("%s ", sha1_to_hex(sha1));
-               if (!delta_chain_length)
+               if (!delta_chain_length) {
                        printf("%-6s %lu %lu %"PRIuMAX"\n",
                               type, size, store_size, (uintmax_t)offset);
+                       baseobjects++;
+               }
                else {
                        printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
                               type, size, store_size, (uintmax_t)offset,
@@ -43,15 +48,21 @@ static void show_pack_info(struct packed_git *p)
                }
        }
 
-       for (i = 0; i <= MAX_CHAIN; i++) {
-               if (!chain_histogram[i])
+       if (baseobjects)
+               printf("non delta: %lu object%s\n",
+                      baseobjects, baseobjects > 1 ? "s" : "");
+
+       for (cnt = 1; cnt <= MAX_CHAIN; cnt++) {
+               if (!chain_histogram[cnt])
                        continue;
-               printf("chain length = %"PRIu32": %"PRIu32" object%s\n", i,
-                      chain_histogram[i], chain_histogram[i] > 1 ? "s" : "");
+               printf("chain length = %d: %lu object%s\n", cnt,
+                      chain_histogram[cnt],
+                      chain_histogram[cnt] > 1 ? "s" : "");
        }
        if (chain_histogram[0])
-               printf("chain length > %d: %"PRIu32" object%s\n", MAX_CHAIN,
-                      chain_histogram[0], chain_histogram[0] > 1 ? "s" : "");
+               printf("chain length > %d: %lu object%s\n", MAX_CHAIN,
+                      chain_histogram[0],
+                      chain_histogram[0] > 1 ? "s" : "");
 }
 
 static int verify_one_pack(const char *path, int verbose)
index 729a159..7f7fda4 100644 (file)
@@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
        close(gpg.in);
        ret = finish_command(&gpg);
 
-       unlink(path);
+       unlink_or_warn(path);
 
        return ret;
 }
index 60d0367..1a6f9d1 100644 (file)
@@ -80,6 +80,7 @@ struct lline {
 /* Lines surviving in the merge result */
 struct sline {
        struct lline *lost_head, **lost_tail;
+       struct lline *next_lost;
        char *bol;
        int len;
        /* bit 0 up to (N-1) are on if the parent has this line (i.e.
@@ -121,18 +122,12 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
 
        /* Check to see if we can squash things */
        if (sline->lost_head) {
-               struct lline *last_one = NULL;
-               /* We cannot squash it with earlier one */
-               for (lline = sline->lost_head;
-                    lline;
-                    lline = lline->next)
-                       if (lline->parent_map & this_mask)
-                               last_one = lline;
-               lline = last_one ? last_one->next : sline->lost_head;
+               lline = sline->next_lost;
                while (lline) {
                        if (lline->len == len &&
                            !memcmp(lline->line, line, len)) {
                                lline->parent_map |= this_mask;
+                               sline->next_lost = lline->next;
                                return;
                        }
                        lline = lline->next;
@@ -147,6 +142,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
        lline->line[len] = 0;
        *sline->lost_tail = lline;
        sline->lost_tail = &lline->next;
+       sline->next_lost = NULL;
 }
 
 struct combine_diff_state {
@@ -168,25 +164,28 @@ static void consume_line(void *state_, char *line, unsigned long len)
                                      &state->nb, &state->nn))
                        return;
                state->lno = state->nb;
-               if (!state->nb)
-                       /* @@ -1,2 +0,0 @@ to remove the
-                        * first two lines...
-                        */
-                       state->nb = 1;
-               if (state->nn == 0)
+               if (state->nn == 0) {
                        /* @@ -X,Y +N,0 @@ removed Y lines
                         * that would have come *after* line N
                         * in the result.  Our lost buckets hang
                         * to the line after the removed lines,
+                        *
+                        * Note that this is correct even when N == 0,
+                        * in which case the hunk removes the first
+                        * line in the file.
                         */
                        state->lost_bucket = &state->sline[state->nb];
-               else
+                       if (!state->nb)
+                               state->nb = 1;
+               } else {
                        state->lost_bucket = &state->sline[state->nb-1];
+               }
                if (!state->sline[state->nb-1].p_lno)
                        state->sline[state->nb-1].p_lno =
                                xcalloc(state->num_parent,
                                        sizeof(unsigned long));
                state->sline[state->nb-1].p_lno[state->n] = state->ob;
+               state->lost_bucket->next_lost = state->lost_bucket->lost_head;
                return;
        }
        if (!state->lost_bucket)
index 1682273..7e5594b 100644 (file)
--- a/config.c
+++ b/config.c
@@ -62,7 +62,8 @@ static char *parse_value(void)
                if (comment)
                        continue;
                if (isspace(c) && !quote) {
-                       space = 1;
+                       if (len)
+                               space++;
                        continue;
                }
                if (!quote) {
@@ -71,11 +72,8 @@ static char *parse_value(void)
                                continue;
                        }
                }
-               if (space) {
-                       if (len)
-                               value[len++] = ' ';
-                       space = 0;
-               }
+               for (; space; space--)
+                       value[len++] = ' ';
                if (c == '\\') {
                        c = get_next_char();
                        switch (c) {
index 4e728bc..25fbe3b 100644 (file)
@@ -385,6 +385,8 @@ AC_SUBST(NO_EXPAT)
 # some Solaris installations).
 # Define NO_ICONV if neither libc nor libiconv support iconv.
 
+if test -z "$NO_ICONV"; then
+
 GIT_STASH_FLAGS($ICONVDIR)
 
 AC_DEFUN([ICONVTEST_SRC], [
@@ -431,6 +433,12 @@ GIT_UNSTASH_FLAGS($ICONVDIR)
 AC_SUBST(NEEDS_LIBICONV)
 AC_SUBST(NO_ICONV)
 
+if test -n "$NO_ICONV"; then
+    NEEDS_LIBICONV=
+fi
+
+fi
+
 #
 # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
 
index f6b8ba6..958c831 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -579,7 +579,10 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
                        git_tcp_connect(fd, host, flags);
                /*
                 * Separate original protocol components prog and path
-                * from extended components with a NUL byte.
+                * from extended host header with a NUL byte.
+                *
+                * Note: Do not add any other headers here!  Doing so
+                * will cause older git-daemon servers to crash.
                 */
                packet_write(fd[1],
                             "%s %s%chost=%s%c",
index 1683e6d..f44152c 100755 (executable)
@@ -99,20 +99,32 @@ __git_ps1 ()
                elif [ -d "$g/rebase-merge" ]; then
                        r="|REBASE-m"
                        b="$(cat "$g/rebase-merge/head-name")"
-               elif [ -f "$g/MERGE_HEAD" ]; then
-                       r="|MERGING"
-                       b="$(git symbolic-ref HEAD 2>/dev/null)"
                else
+                       if [ -f "$g/MERGE_HEAD" ]; then
+                               r="|MERGING"
+                       fi
                        if [ -f "$g/BISECT_LOG" ]; then
                                r="|BISECTING"
                        fi
-                       if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then
-                               if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then
-                                       if [ -r "$g/HEAD" ]; then
-                                               b="$(cut -c1-7 "$g/HEAD")..."
-                                       fi
-                               fi
-                       fi
+
+                       b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+                               b="$(
+                               case "${GIT_PS1_DESCRIBE_STYLE-}" in
+                               (contains)
+                                       git describe --contains HEAD ;;
+                               (branch)
+                                       git describe --contains --all HEAD ;;
+                               (describe)
+                                       git describe HEAD ;;
+                               (* | default)
+                                       git describe --exact-match HEAD ;;
+                               esac 2>/dev/null)" ||
+
+                               b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+                               b="unknown"
+                               b="($b)"
+                       }
                fi
 
                local w
@@ -120,7 +132,7 @@ __git_ps1 ()
                local c
 
                if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
-                       if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
+                       if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
                                c="BARE:"
                        else
                                b="GIT_DIR!"
@@ -1792,7 +1804,7 @@ _git_show ()
                return
                ;;
        --*)
-               __gitcomp "--pretty= --format=
+               __gitcomp "--pretty= --format= --abbrev-commit --oneline
                        $__git_diff_common_options
                        "
                return
@@ -1809,7 +1821,7 @@ _git_show_branch ()
                __gitcomp "
                        --all --remotes --topo-order --current --more=
                        --list --independent --merge-base --no-name
-                       --sha1-name --topics --reflog
+                       --sha1-name --sparse --topics --reflog
                        "
                return
                ;;
index 6309d14..78e40d2 100755 (executable)
@@ -82,10 +82,16 @@ foreach my $tar_file (@ARGV)
                $mtime = oct $mtime;
                next if $typeflag == 5; # directory
 
-               print FI "blob\n", "mark :$next_mark\n", "data $size\n";
-               while ($size > 0 && read(I, $_, 512) == 512) {
-                       print FI substr($_, 0, $size);
-                       $size -= 512;
+               print FI "blob\n", "mark :$next_mark\n";
+               if ($typeflag == 2) { # symbolic link
+                       print FI "data ", length($linkname), "\n", $linkname;
+                       $mode = 0120000;
+               } else {
+                       print FI "data $size\n";
+                       while ($size > 0 && read(I, $_, 512) == 512) {
+                               print FI substr($_, 0, $size);
+                               $size -= 512;
+                       }
                }
                print FI "\n";
 
@@ -118,7 +124,8 @@ EOF
        {
                my ($mark, $mode) = @{$files{$path}};
                $path =~ s,^([^/]+)/,, if $have_top_dir;
-               printf FI "M %o :%i %s\n", $mode & 0111 ? 0755 : 0644, $mark, $path;
+               $mode = $mode & 0111 ? 0755 : 0644 unless $mode == 0120000;
+               printf FI "M %o :%i %s\n", $mode, $mark, $path;
        }
        print FI "\n";
 
index 7b03204..2a6839d 100755 (executable)
@@ -20,7 +20,7 @@
 """
 
 import os, os.path, sys
-import tempfile, popen2, pickle, getopt
+import tempfile, pickle, getopt
 import re
 
 # Maps hg version -> git version
index daa4c8e..b2babcc 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -406,15 +406,15 @@ static char *xstrdup_tolower(const char *str)
 }
 
 /*
- * Separate the "extra args" information as supplied by the client connection.
+ * Read the host as supplied by the client connection.
  */
-static void parse_extra_args(char *extra_args, int buflen)
+static void parse_host_arg(char *extra_args, int buflen)
 {
        char *val;
        int vallen;
        char *end = extra_args + buflen;
 
-       while (extra_args < end && *extra_args) {
+       if (extra_args < end && *extra_args) {
                saw_extended_args = 1;
                if (strncasecmp("host=", extra_args, 5) == 0) {
                        val = extra_args + 5;
@@ -436,6 +436,8 @@ static void parse_extra_args(char *extra_args, int buflen)
                        /* On to the next one */
                        extra_args = val + vallen;
                }
+               if (extra_args < end && *extra_args)
+                       die("Invalid request");
        }
 
        /*
@@ -545,7 +547,7 @@ static int execute(struct sockaddr *addr)
        hostname = canon_hostname = ip_address = tcp_port = NULL;
 
        if (len != pktlen)
-               parse_extra_args(line + len + 1, pktlen - len - 1);
+               parse_host_arg(line + len + 1, pktlen - len - 1);
 
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                struct daemon_service *s = &(daemon_service[i]);
index 82d9e22..e6fd8a7 100644 (file)
@@ -8,7 +8,9 @@
 
 static unsigned int hash_obj(const struct object *obj, unsigned int n)
 {
-       unsigned int hash = *(unsigned int *)obj->sha1;
+       unsigned int hash;
+
+       memcpy(&hash, obj->sha1, sizeof(unsigned int));
        return hash % n;
 }
 
diff --git a/delta.h b/delta.h
index 40ccf5a..b9d333d 100644 (file)
--- a/delta.h
+++ b/delta.h
@@ -90,12 +90,11 @@ static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
                                               const unsigned char *top)
 {
        const unsigned char *data = *datap;
-       unsigned char cmd;
-       unsigned long size = 0;
+       unsigned long cmd, size = 0;
        int i = 0;
        do {
                cmd = *data++;
-               size |= (cmd & ~0x80) << i;
+               size |= (cmd & 0x7f) << i;
                i += 7;
        } while (cmd & 0x80 && data < top);
        *datap = data;
index a310fb2..0aba6cd 100644 (file)
@@ -214,7 +214,7 @@ static int get_stat_data(struct cache_entry *ce,
        const unsigned char *sha1 = ce->sha1;
        unsigned int mode = ce->ce_mode;
 
-       if (!cached) {
+       if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
                changed = check_removed(ce, &st);
diff --git a/diff.c b/diff.c
index 363dcb9..f0b580c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -189,7 +189,7 @@ static void remove_tempfile(void)
        int i;
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
                if (diff_temp[i].name == diff_temp[i].tmp_path)
-                       unlink(diff_temp[i].name);
+                       unlink_or_warn(diff_temp[i].name);
                diff_temp[i].name = NULL;
        }
 }
@@ -3590,6 +3590,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        if (start_command(&child) != 0 ||
            strbuf_read(&buf, child.out, 0) < 0 ||
            finish_command(&child) != 0) {
+               strbuf_release(&buf);
                remove_tempfile();
                error("error running textconv command '%s'", pgm);
                return NULL;
diff --git a/dir.c b/dir.c
index 6aae09a..0e6b752 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path)
  */
 static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
 {
-       DIR *fdir = opendir(path);
+       DIR *fdir = opendir(*path ? path : ".");
        int contents = 0;
 
        if (fdir) {
diff --git a/entry.c b/entry.c
index 915514a..cc841ed 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len,
                 */
                if (mkdir(buf, 0777)) {
                        if (errno == EEXIST && state->force &&
-                           !unlink(buf) && !mkdir(buf, 0777))
+                           !unlink_or_warn(buf) && !mkdir(buf, 0777))
                                continue;
                        die("cannot create directory at %s", buf);
                }
index e9d23ff..a2a2458 100644 (file)
@@ -931,7 +931,7 @@ static void unkeep_all_packs(void)
                struct packed_git *p = all_packs[k];
                snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
                         get_object_directory(), sha1_to_hex(p->sha1));
-               unlink(name);
+               unlink_or_warn(name);
        }
 }
 
@@ -981,7 +981,7 @@ static void end_packfile(void)
        }
        else {
                close(old_p->pack_fd);
-               unlink(old_p->pack_name);
+               unlink_or_warn(old_p->pack_name);
        }
        free(old_p);
 
index e6f93c7..06f7060 100755 (executable)
@@ -1321,7 +1321,6 @@ sub patch_update_file {
                open $fh, '| git apply --cached --recount';
                for (@{$head->{TEXT}}, @result) {
                        print $fh $_;
-                       print STDERR $_;
                }
                if (!close $fh) {
                        for (@{$head->{TEXT}}, @result) {
index 1ac16bd..c7cf2d5 100644 (file)
@@ -415,4 +415,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 #define fstat_is_reliable() 1
 #endif
 
+/*
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Always returns the return value of unlink(2).
+ */
+int unlink_or_warn(const char *path);
+
 #endif
index 3526153..cab367a 100755 (executable)
@@ -176,13 +176,11 @@ case "$merge_head" in
 ?*' '?*)
        if test -z "$orig_head"
        then
-               echo >&2 "Cannot merge multiple branches into empty head"
-               exit 1
+               die "Cannot merge multiple branches into empty head"
        fi
        if test true = "$rebase"
        then
-               echo >&2 "Cannot rebase onto multiple branches"
-               exit 1
+               die "Cannot rebase onto multiple branches"
        fi
        ;;
 esac
index 314cd36..f96d887 100755 (executable)
@@ -420,7 +420,7 @@ do_next () {
        NEWHEAD=$(git rev-parse HEAD) &&
        case $HEADNAME in
        refs/*)
-               message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)" &&
+               message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO" &&
                git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD &&
                git symbolic-ref HEAD $HEADNAME
                ;;
index b83fd3f..334629f 100755 (executable)
@@ -168,10 +168,8 @@ run_pre_rebase_hook () {
        if test -z "$OK_TO_SKIP_PRE_REBASE" &&
           test -x "$GIT_DIR/hooks/pre-rebase"
        then
-               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
-                       echo >&2 "The pre-rebase hook refused to rebase."
-                       exit 1
-               }
+               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
+               die "The pre-rebase hook refused to rebase."
        fi
 }
 
@@ -359,8 +357,7 @@ fi
 
 # The tree must be really really clean.
 if ! git update-index --ignore-submodules --refresh; then
-       echo >&2 "cannot rebase: you have unstaged changes"
-       exit 1
+       die "cannot rebase: you have unstaged changes"
 fi
 diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)
 case "$diff" in
index a2cf5b8..fd95bea 100755 (executable)
@@ -12,6 +12,9 @@ OPTIONS_SPEC=
 . git-sh-setup
 . git-parse-remote
 
+GIT_PAGER=
+export GIT_PAGER
+
 base=$1
 url=$2
 head=${3-HEAD}
@@ -25,16 +28,16 @@ headrev=`git rev-parse --verify "$head"^0` || exit
 merge_base=`git merge-base $baserev $headrev` ||
 die "fatal: No commits in common between $base and $head"
 
-url=$(get_remote_url "$url")
 branch=$(git ls-remote "$url" \
        | sed -n -e "/^$headrev refs.heads./{
                s/^.*   refs.heads.//
                p
                q
        }")
+url=$(get_remote_url "$url")
 if [ -z "$branch" ]; then
        echo "warn: No branch of $url is at:" >&2
-       git log --max-count=1 --pretty='format:warn:   %h: %s' $headrev >&2
+       git log --max-count=1 --pretty='tformat:warn:   %h: %s' $headrev >&2
        echo "warn: Are you sure you pushed $head there?" >&2
        echo >&2
        echo >&2
@@ -42,8 +45,6 @@ if [ -z "$branch" ]; then
        status=1
 fi
 
-PAGER=
-export PAGER
 echo "The following changes since commit $baserev:"
 git shortlog --max-count=1 $baserev | sed -e 's/^\(.\)/  \1/'
 
index cccbf45..17f930f 100755 (executable)
@@ -449,7 +449,6 @@ sub check_file_rev_conflict($) {
        try {
                $repo->command('rev-parse', '--verify', '--quiet', $f);
                if (defined($format_patch)) {
-                       print "foo\n";
                        return $format_patch;
                }
                die(<<EOF);
index ccda890..9056d1e 100644 (file)
@@ -377,7 +377,7 @@ named without a .git extension (e.g. /pub/git/project instead of
 
        DocumentRoot /var/www/gitweb
 
-       AliasMatch ^(/.*?)(\.git)(/.*)? /pub/git$1$3
+       AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
        <Directory /var/www/gitweb>
                Options ExecCGI
                AddHandler cgi-script cgi
@@ -402,6 +402,14 @@ http://git.example.com/project
 
 will provide human-friendly gitweb access.
 
+This solution is not 100% bulletproof, in the sense that if some project
+has a named ref (branch, tag) starting with 'git/', then paths such as
+
+http://git.example.com/project/command/abranch..git/abranch
+
+will fail with a 404 error.
+
+
 
 Originally written by:
   Kay Sievers <kay.sievers@vrfy.org>
diff --git a/grep.c b/grep.c
index 04c777a..92a47c7 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -305,6 +305,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
 {
        int hit = 0;
        int saved_ch = 0;
+       const char *start = bol;
 
        if ((p->token != GREP_PATTERN) &&
            ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
@@ -330,7 +331,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
 
        if (hit && p->word_regexp) {
                if ((pmatch[0].rm_so < 0) ||
-                   (eol - bol) <= pmatch[0].rm_so ||
+                   (eol - bol) < pmatch[0].rm_so ||
                    (pmatch[0].rm_eo < 0) ||
                    (eol - bol) < pmatch[0].rm_eo)
                        die("regexp returned nonsense");
@@ -349,6 +350,10 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
                else
                        hit = 0;
 
+               /* Words consist of at least one character. */
+               if (pmatch->rm_so == pmatch->rm_eo)
+                       hit = 0;
+
                if (!hit && pmatch[0].rm_so + bol + 1 < eol) {
                        /* There could be more than one match on the
                         * line, and the first match might not be
@@ -359,12 +364,17 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
                        bol = pmatch[0].rm_so + bol + 1;
                        while (word_char(bol[-1]) && bol < eol)
                                bol++;
+                       eflags |= REG_NOTBOL;
                        if (bol < eol)
                                goto again;
                }
        }
        if (p->token == GREP_PATTERN_HEAD && saved_ch)
                *eol = saved_ch;
+       if (hit) {
+               pmatch[0].rm_so += bol - start;
+               pmatch[0].rm_eo += bol - start;
+       }
        return hit;
 }
 
@@ -494,6 +504,8 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
 
                *eol = '\0';
                while (next_match(opt, bol, eol, ctx, &match, eflags)) {
+                       if (match.rm_so == match.rm_eo)
+                               break;
                        printf("%.*s%s%.*s%s",
                               (int)match.rm_so, bol,
                               opt->color_match,
diff --git a/help.c b/help.c
index fd87bb5..da0cca0 100644 (file)
--- a/help.c
+++ b/help.c
@@ -302,7 +302,7 @@ const char *help_unknown_cmd(const char *cmd)
        struct cmdnames main_cmds, other_cmds;
 
        memset(&main_cmds, 0, sizeof(main_cmds));
-       memset(&other_cmds, 0, sizeof(main_cmds));
+       memset(&other_cmds, 0, sizeof(other_cmds));
        memset(&aliases, 0, sizeof(aliases));
 
        git_config(git_unknown_cmd_config, NULL);
@@ -334,7 +334,7 @@ const char *help_unknown_cmd(const char *cmd)
                const char *assumed = main_cmds.names[0]->name;
                main_cmds.names[0] = NULL;
                clean_cmdnames(&main_cmds);
-               fprintf(stderr, "WARNING: You called a Git program named '%s', "
+               fprintf(stderr, "WARNING: You called a Git command named '%s', "
                        "which does not exist.\n"
                        "Continuing under the assumption that you meant '%s'\n",
                        cmd, assumed);
index 5138224..0b12ffe 100644 (file)
@@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request)
                 "%s.temp", filename);
 
        snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
        rename(request->tmpfile, prevfile);
-       unlink(request->tmpfile);
+       unlink_or_warn(request->tmpfile);
 
        if (request->local_fileno != -1)
                error("fd leakage in start: %d", request->local_fileno);
@@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request)
                } while (prev_read > 0);
                close(prevlocal);
        }
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
 
        /* Reset inflate/SHA1 if there was an error reading the previous temp
           file; also rewind to the beginning of the local file. */
@@ -724,9 +724,11 @@ static void finish_request(struct transfer_request *request)
        struct stat st;
        struct packed_git *target;
        struct packed_git **lst;
+       struct active_request_slot *slot;
 
        request->curl_result = request->slot->curl_result;
        request->http_code = request->slot->http_code;
+       slot = request->slot;
        request->slot = NULL;
 
        /* Keep locks active */
@@ -784,7 +786,7 @@ static void finish_request(struct transfer_request *request)
                    request->http_code != 416) {
                        if (stat(request->tmpfile, &st) == 0) {
                                if (st.st_size == 0)
-                                       unlink(request->tmpfile);
+                                       unlink_or_warn(request->tmpfile);
                        }
                } else {
                        if (request->http_code == 416)
@@ -793,9 +795,9 @@ static void finish_request(struct transfer_request *request)
                        git_inflate_end(&request->stream);
                        git_SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
-                               unlink(request->tmpfile);
+                               unlink_or_warn(request->tmpfile);
                        } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
-                               unlink(request->tmpfile);
+                               unlink_or_warn(request->tmpfile);
                        } else {
                                request->rename =
                                        move_temp_to_file(
@@ -823,6 +825,7 @@ static void finish_request(struct transfer_request *request)
 
                        fclose(request->local_stream);
                        request->local_stream = NULL;
+                       slot->local = NULL;
                        if (!move_temp_to_file(request->tmpfile,
                                               request->filename)) {
                                target = (struct packed_git *)request->userData;
@@ -1024,17 +1027,20 @@ static int fetch_index(unsigned char *sha1)
                if (results.curl_result != CURLE_OK) {
                        free(url);
                        fclose(indexfile);
+                       slot->local = NULL;
                        return error("Unable to get pack index %s\n%s", url,
                                     curl_errorstr);
                }
        } else {
                free(url);
                fclose(indexfile);
+               slot->local = NULL;
                return error("Unable to start request");
        }
 
        free(url);
        fclose(indexfile);
+       slot->local = NULL;
 
        return move_temp_to_file(tmpfile, filename);
 }
@@ -1415,8 +1421,9 @@ static void remove_locks(void)
 
        fprintf(stderr, "Removing remote locks...\n");
        while (lock) {
+               struct remote_lock *next = lock->next;
                unlock_remote(lock);
-               lock = lock->next;
+               lock = next;
        }
 }
 
index c5a3ea3..9377851 100644 (file)
@@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker,
        struct walker_data *data = walker->data;
 
        snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
        rename(obj_req->tmpfile, prevfile);
-       unlink(obj_req->tmpfile);
+       unlink_or_warn(obj_req->tmpfile);
 
        if (obj_req->local != -1)
                error("fd leakage in start: %d", obj_req->local);
@@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker,
                } while (prev_read > 0);
                close(prevlocal);
        }
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
 
        /* Reset inflate/SHA1 if there was an error reading the previous temp
           file; also rewind to the beginning of the local file. */
@@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req)
        } else if (obj_req->curl_result != CURLE_OK) {
                if (stat(obj_req->tmpfile, &st) == 0)
                        if (st.st_size == 0)
-                               unlink(obj_req->tmpfile);
+                               unlink_or_warn(obj_req->tmpfile);
                return;
        }
 
        git_inflate_end(&obj_req->stream);
        git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
        if (obj_req->zret != Z_STREAM_END) {
-               unlink(obj_req->tmpfile);
+               unlink_or_warn(obj_req->tmpfile);
                return;
        }
        if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
-               unlink(obj_req->tmpfile);
+               unlink_or_warn(obj_req->tmpfile);
                return;
        }
        obj_req->rename =
@@ -418,15 +418,18 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
                        fclose(indexfile);
+                       slot->local = NULL;
                        return error("Unable to get pack index %s\n%s", url,
                                     curl_errorstr);
                }
        } else {
                fclose(indexfile);
+               slot->local = NULL;
                return error("Unable to start request");
        }
 
        fclose(indexfile);
+       slot->local = NULL;
 
        return move_temp_to_file(tmpfile, filename);
 }
@@ -776,16 +779,19 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
                        fclose(packfile);
+                       slot->local = NULL;
                        return error("Unable to get pack file %s\n%s", url,
                                     curl_errorstr);
                }
        } else {
                fclose(packfile);
+               slot->local = NULL;
                return error("Unable to start request");
        }
 
        target->pack_size = ftell(packfile);
        fclose(packfile);
+       slot->local = NULL;
 
        ret = move_temp_to_file(tmpfile, filename);
        if (ret)
@@ -809,7 +815,7 @@ static void abort_object_request(struct object_request *obj_req)
                close(obj_req->local);
                obj_req->local = -1;
        }
-       unlink(obj_req->tmpfile);
+       unlink_or_warn(obj_req->tmpfile);
        if (obj_req->slot) {
                release_active_slot(obj_req->slot);
                obj_req->slot = NULL;
diff --git a/http.c b/http.c
index 2e3d649..b5323a6 100644 (file)
--- a/http.c
+++ b/http.c
@@ -14,7 +14,7 @@ char curl_errorstr[CURL_ERROR_SIZE];
 
 static int curl_ssl_verify = -1;
 static const char *ssl_cert;
-#if LIBCURL_VERSION_NUM >= 0x070902
+#if LIBCURL_VERSION_NUM >= 0x070903
 static const char *ssl_key;
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
@@ -119,7 +119,7 @@ static int http_options(const char *var, const char *value, void *cb)
        }
        if (!strcmp("http.sslcert", var))
                return git_config_string(&ssl_cert, var, value);
-#if LIBCURL_VERSION_NUM >= 0x070902
+#if LIBCURL_VERSION_NUM >= 0x070903
        if (!strcmp("http.sslkey", var))
                return git_config_string(&ssl_key, var, value);
 #endif
@@ -189,7 +189,7 @@ static CURL *get_curl_handle(void)
 
        if (ssl_cert != NULL)
                curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
-#if LIBCURL_VERSION_NUM >= 0x070902
+#if LIBCURL_VERSION_NUM >= 0x070903
        if (ssl_key != NULL)
                curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
 #endif
@@ -303,7 +303,7 @@ void http_init(struct remote *remote)
                curl_ssl_verify = 0;
 
        set_from_env(&ssl_cert, "GIT_SSL_CERT");
-#if LIBCURL_VERSION_NUM >= 0x070902
+#if LIBCURL_VERSION_NUM >= 0x070903
        set_from_env(&ssl_key, "GIT_SSL_KEY");
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
index 6e93ee6..0c92baf 100644 (file)
@@ -293,8 +293,8 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size)
 
 static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
 {
-       unsigned char *p, c;
-       unsigned long size;
+       unsigned char *p;
+       unsigned long size, c;
        off_t base_offset;
        unsigned shift;
        void *data;
@@ -312,7 +312,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                p = fill(1);
                c = *p;
                use(1);
-               size += (c & 0x7fUL) << shift;
+               size += (c & 0x7f) << shift;
                shift += 7;
        }
        obj->size = size;
index fa2ca52..f7c2bc9 100644 (file)
@@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
        close(fd);
  bad:
        for (i = 0; i < 3; i++)
-               unlink(temp[i]);
+               unlink_or_warn(temp[i]);
        strbuf_release(&cmd);
        return status;
 }
@@ -238,7 +238,7 @@ static int read_merge_config(const char *var, const char *value, void *cb)
 
        if (!strcmp(var, "merge.default")) {
                if (value)
-                       default_ll_merge = strdup(value);
+                       default_ll_merge = xstrdup(value);
                return 0;
        }
 
@@ -272,7 +272,7 @@ static int read_merge_config(const char *var, const char *value, void *cb)
        if (!strcmp("name", ep)) {
                if (!value)
                        return error("%s: lacks value", var);
-               fn->description = strdup(value);
+               fn->description = xstrdup(value);
                return 0;
        }
 
@@ -295,14 +295,14 @@ static int read_merge_config(const char *var, const char *value, void *cb)
                 * file named by %A, and signal that it has done with zero exit
                 * status.
                 */
-               fn->cmdline = strdup(value);
+               fn->cmdline = xstrdup(value);
                return 0;
        }
 
        if (!strcmp("recursive", ep)) {
                if (!value)
                        return error("%s: lacks value", var);
-               fn->recursive = strdup(value);
+               fn->recursive = xstrdup(value);
                return 0;
        }
 
index 828d19f..eb931ed 100644 (file)
@@ -16,7 +16,7 @@ static void remove_lock_file(void)
                    lock_file_list->filename[0]) {
                        if (lock_file_list->fd >= 0)
                                close(lock_file_list->fd);
-                       unlink(lock_file_list->filename);
+                       unlink_or_warn(lock_file_list->filename);
                }
                lock_file_list = lock_file_list->next;
        }
@@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk)
        if (lk->filename[0]) {
                if (lk->fd >= 0)
                        close(lk->fd);
-               unlink(lk->filename);
+               unlink_or_warn(lk->filename);
        }
        lk->filename[0] = 0;
 }
index a3721ef..f5df9b9 100644 (file)
@@ -933,11 +933,12 @@ static int process_renames(struct merge_options *o,
                                       ren1_src, ren1_dst, branch1,
                                       branch2);
                                update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
-                               update_stages(ren1_dst, NULL,
-                                               branch1 == o->branch1 ?
-                                               ren1->pair->two : NULL,
-                                               branch1 == o->branch1 ?
-                                               NULL : ren1->pair->two, 1);
+                               if (!o->call_depth)
+                                       update_stages(ren1_dst, NULL,
+                                                       branch1 == o->branch1 ?
+                                                       ren1->pair->two : NULL,
+                                                       branch1 == o->branch1 ?
+                                                       NULL : ren1->pair->two, 1);
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                const char *new_path;
                                clean_merge = 0;
index 7e6a92c..e1feef9 100644 (file)
--- a/object.c
+++ b/object.c
@@ -45,7 +45,8 @@ int type_from_string(const char *str)
 
 static unsigned int hash_obj(struct object *obj, unsigned int n)
 {
-       unsigned int hash = *(unsigned int *)obj->sha1;
+       unsigned int hash;
+       memcpy(&hash, obj->sha1, sizeof(unsigned int));
        return hash % n;
 }
 
index 2c76fb1..301fc60 100644 (file)
@@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r)
        struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
 
        if (lock) {
-               unlink(git_path("%s", r->name));
+               unlink_or_warn(git_path("%s", r->name));
                unlock_ref(lock);
        }
 }
index ed9db81..ef748ce 100644 (file)
@@ -44,7 +44,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
                        if (cmd & 0x01) cp_off = *data++;
                        if (cmd & 0x02) cp_off |= (*data++ << 8);
                        if (cmd & 0x04) cp_off |= (*data++ << 16);
-                       if (cmd & 0x08) cp_off |= (*data++ << 24);
+                       if (cmd & 0x08) cp_off |= ((unsigned) *data++ << 24);
                        if (cmd & 0x10) cp_size = *data++;
                        if (cmd & 0x20) cp_size |= (*data++ << 8);
                        if (cmd & 0x40) cp_size |= (*data++ << 16);
diff --git a/refs.c b/refs.c
index e65a3b4..3da3c8c 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -531,9 +531,10 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
 {
        if (strncmp(base, entry->name, trim))
                return 0;
+       /* Is this a "negative ref" that represents a deleted ref? */
+       if (is_null_sha1(entry->sha1))
+               return 0;
        if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
-               if (is_null_sha1(entry->sha1))
-                       return 0;
                if (!has_sha1_file(entry->sha1)) {
                        error("%s does not point to a valid object!", entry->name);
                        return 0;
@@ -893,8 +894,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
         * name is a proper prefix of our refname.
         */
        if (missing &&
-            !is_refname_available(ref, NULL, get_packed_refs(), 0))
+            !is_refname_available(ref, NULL, get_packed_refs(), 0)) {
+               last_errno = ENOTDIR;
                goto error_return;
+       }
 
        lock->lk = xcalloc(1, sizeof(struct lock_file));
 
@@ -1002,12 +1005,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
                } else {
                        path = git_path("%s", refname);
                }
-               err = unlink(path);
-               if (err && errno != ENOENT) {
+               err = unlink_or_warn(path);
+               if (err && errno != ENOENT)
                        ret = 1;
-                       error("unlink(%s) failed: %s",
-                             path, strerror(errno));
-               }
+
                if (!(delopt & REF_NODEREF))
                        lock->lk->filename[i] = '.';
        }
@@ -1017,10 +1018,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
         */
        ret |= repack_without_ref(refname);
 
-       err = unlink(git_path("logs/%s", lock->ref_name));
-       if (err && errno != ENOENT)
-               warning("unlink(%s) failed: %s",
-                       git_path("logs/%s", lock->ref_name), strerror(errno));
+       unlink_or_warn(git_path("logs/%s", lock->ref_name));
        invalidate_cached_refs();
        unlock_ref(lock);
        return ret;
@@ -1381,7 +1379,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
        if (adjust_shared_perm(git_HEAD)) {
                error("Unable to fix permissions on %s", lockpath);
        error_unlink_return:
-               unlink(lockpath);
+               unlink_or_warn(lockpath);
        error_free_return:
                free(git_HEAD);
                return -1;
@@ -1528,8 +1526,10 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
                if (fstat(fileno(logfp), &statbuf) ||
                    statbuf.st_size < ofs ||
                    fseek(logfp, -ofs, SEEK_END) ||
-                   fgets(buf, sizeof(buf), logfp))
+                   fgets(buf, sizeof(buf), logfp)) {
+                       fclose(logfp);
                        return -1;
+               }
        }
 
        while (fgets(buf, sizeof(buf), logfp)) {
index d66e2f3..39583d5 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1254,7 +1254,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
 
 static struct ref *get_local_ref(const char *name)
 {
-       if (!name)
+       if (!name || name[0] == '\0')
                return NULL;
 
        if (!prefixcmp(name, "refs/"))
index 713c6e1..87360dc 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -173,7 +173,7 @@ static int handle_file(const char *path,
                git_SHA1_Final(sha1, &ctx);
        if (hunk != RR_CONTEXT) {
                if (output)
-                       unlink(output);
+                       unlink_or_warn(output);
                return error("Could not parse conflict hunks in %s", path);
        }
        if (wrerror)
index 83d76c7..1d7b1b3 100644 (file)
@@ -6,6 +6,7 @@ struct send_pack_args {
                send_mirror:1,
                force_update:1,
                use_thin_pack:1,
+               use_ofs_delta:1,
                dry_run:1;
 };
 
index 906ce5b..4098ca2 100644 (file)
@@ -246,7 +246,7 @@ int update_server_info(int force)
        errs = errs | update_info_packs(force);
 
        /* remove leftover rev-cache file if there is any */
-       unlink(git_path("info/rev-cache"));
+       unlink_or_warn(git_path("info/rev-cache"));
 
        return errs;
 }
index 28bd908..8f5fe62 100644 (file)
@@ -720,6 +720,8 @@ static int open_packed_git_1(struct packed_git *p)
                return error("packfile %s index unavailable", p->pack_name);
 
        p->pack_fd = open(p->pack_name, O_RDONLY);
+       while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
+               p->pack_fd = open(p->pack_name, O_RDONLY);
        if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
                return -1;
 
@@ -937,6 +939,8 @@ static void prepare_packed_git_one(char *objdir, int local)
        sprintf(path, "%s/pack", objdir);
        len = strlen(path);
        dir = opendir(path);
+       while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
+               dir = opendir(path);
        if (!dir) {
                if (errno != ENOENT)
                        error("unable to open object pack directory: %s: %s",
@@ -1158,8 +1162,7 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
                unsigned long len, enum object_type *type, unsigned long *sizep)
 {
        unsigned shift;
-       unsigned char c;
-       unsigned long size;
+       unsigned long size, c;
        unsigned long used = 0;
 
        c = buf[used++];
@@ -2247,7 +2250,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
                        goto out;
                ret = errno;
        }
-       unlink(tmpfile);
+       unlink_or_warn(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
                        return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
@@ -2339,6 +2342,8 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
 
        filename = sha1_file_name(sha1);
        fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
+       while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
+               fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
index 904bcd9..44bb62d 100644 (file)
@@ -777,8 +777,6 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
        for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb);
        if (cb.cnt < nth) {
                cb.cnt = 0;
-               for (i = 0; i < nth; i++)
-                       strbuf_release(&cb.buf[i]);
                for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
        }
        if (cb.cnt < nth)
index a884960..f03d117 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -260,7 +260,7 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
        res = fread(sb->buf + sb->len, 1, size, f);
        if (res > 0)
                strbuf_setlen(sb, sb->len + res);
-       else if (res < 0 && oldalloc == 0)
+       else if (oldalloc == 0)
                strbuf_release(sb);
        return res;
 }
index 43ea283..91cbd55 100755 (executable)
@@ -733,6 +733,11 @@ echo >>result
 
 test_expect_success '--null --get-regexp' 'cmp result expect'
 
+test_expect_success 'inner whitespace kept verbatim' '
+       git config section.val "foo       bar" &&
+       test "z$(git config section.val)" = "zfoo         bar"
+'
+
 test_expect_success SYMLINKS 'symlinked configuration' '
 
        ln -s notyet myconfig &&
index 0de613d..9b3fa2b 100755 (executable)
@@ -276,6 +276,9 @@ test_expect_success 'fail if the index has unresolved entries' '
 
        test_must_fail git merge "$c5" &&
        test_must_fail git merge "$c5" 2> out &&
+       grep "You have not concluded your merge" out &&
+       rm -f .git/MERGE_HEAD &&
+       test_must_fail git merge "$c5" 2> out &&
        grep "You are in the middle of a conflicted merge" out
 
 '
diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh
new file mode 100755 (executable)
index 0000000..7f41607
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+#         A      <- create some files
+#        / \
+#       B   C    <- cause rename/delete conflicts between B and C
+#      /     \
+#     |\     /|
+#     | D   E |
+#     |  \ /  |
+#     |   X   |
+#     |  / \  |
+#     | /   \ |
+#     |/     \|
+#     F       G  <- merge E into B, D into C
+#      \     /
+#       \   /
+#        \ /
+#         H      <- recursive merge crashes
+#
+
+# initialize
+test_expect_success 'setup repo with criss-cross history' '
+       mkdir data &&
+
+       # create a bunch of files
+       n=1 &&
+       while test $n -le 10
+       do
+               echo $n > data/$n &&
+               n=$(($n+1)) ||
+               break
+       done &&
+
+       # check them in
+       git add data &&
+       git commit -m A &&
+       git branch A &&
+
+       # a file in one branch
+       git checkout -b B A &&
+       git rm data/9 &&
+       git add data &&
+       git commit -m B &&
+
+       # with a branch off of it
+       git branch D &&
+
+       # put some commits on D
+       git checkout D &&
+       echo testD > data/testD &&
+       git add data &&
+       git commit -m D &&
+
+       # back up to the top, create another branch and cause
+       # a rename conflict with the file we deleted earlier
+       git checkout -b C A &&
+       git mv data/9 data/new-9 &&
+       git add data &&
+       git commit -m C &&
+
+       # with a branch off of it
+       git branch E &&
+
+       # put a commit on E
+       git checkout E &&
+       echo testE > data/testE &&
+       git add data &&
+       git commit -m E &&
+
+       # now, merge E into B
+       git checkout B &&
+       test_must_fail git merge E &&
+       # force-resolve
+       git add data &&
+       git commit -m F &&
+       git branch F &&
+
+       # and merge D into C
+       git checkout C &&
+       test_must_fail git merge D &&
+       # force-resolve
+       git add data &&
+       git commit -m G &&
+       git branch G
+'
+
+test_expect_success 'recursive merge between F and G, causes segfault' '
+       git merge F
+'
+
+test_done
index 9aaeabd..e51e505 100755 (executable)
@@ -17,11 +17,11 @@ test_expect_success setup '
 
 '
 
-test_expect_code 1 'cherry-pick an empty commit' '
-
-       git checkout master &&
-       git cherry-pick empty-branch
-
+test_expect_success 'cherry-pick an empty commit' '
+       git checkout master && {
+               git cherry-pick empty-branch
+               test "$?" = 1
+       }
 '
 
 test_expect_success 'index lockfile was removed' '
index 050de42..fe93ce5 100755 (executable)
@@ -221,6 +221,19 @@ test_expect_success POSIXPERM 'git add (add.ignore-errors = false)' '
        test_must_fail git add --verbose . &&
        ! ( git ls-files foo1 | grep foo1 )
 '
+rm -f foo2
+
+test_expect_success POSIXPERM '--no-ignore-errors overrides config' '
+       git config add.ignore-errors 1 &&
+       git reset --hard &&
+       date >foo1 &&
+       date >foo2 &&
+       chmod 0 foo2 &&
+       test_must_fail git add --verbose --no-ignore-errors . &&
+       ! ( git ls-files foo1 | grep foo1 ) &&
+       git config add.ignore-errors 0
+'
+rm -f foo2
 
 test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" '
        git reset --hard &&
index 63940b1..62fd65e 100755 (executable)
@@ -176,6 +176,12 @@ test_expect_success FILEMODE 'stage mode and hunk' '
 
 # end of tests disabled when filemode is not usable
 
+test_expect_success 'setup again' '
+       git reset --hard &&
+       test_chmod +x file &&
+       echo content >>file
+'
+
 # Write the patch file with a new line at the top and bottom
 cat >patch <<EOF
 index 180b47c..b6f2c08 100644
index 11061dd..922a894 100755 (executable)
@@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' '
        test -f "$basename"
 '
 
+test_expect_success 'format-patch --in-reply-to' '
+       git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
+       grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
+       grep "^References: <baz@foo.bar>" patch8
+'
+
+test_expect_success 'format-patch --signoff' '
+       git format-patch -1 --signoff --stdout |
+       grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+'
+
 test_done
index 390af23..709b323 100755 (executable)
@@ -86,6 +86,13 @@ test_expect_success 'format.numbered && --no-numbered' '
 
 '
 
+test_expect_success 'format.numbered && --keep-subject' '
+
+       git format-patch --keep-subject --stdout HEAD^ >patch4a &&
+       grep "^Subject: Third" patch4a
+
+'
+
 test_expect_success 'format.numbered = auto' '
 
        git config format.numbered auto
@@ -108,4 +115,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' '
 
 '
 
+test_expect_success '--start-number && --numbered' '
+
+       git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 &&
+       grep "^Subject: \[PATCH 3/3\]" patch8
+'
+
 test_done
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
new file mode 100755 (executable)
index 0000000..2cf7e01
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+test_description='combined diff'
+
+. ./test-lib.sh
+
+setup_helper () {
+       one=$1 branch=$2 side=$3 &&
+
+       git branch $side $branch &&
+       for l in $one two three fyra
+       do
+               echo $l
+       done >file &&
+       git add file &&
+       test_tick &&
+       git commit -m $branch &&
+       git checkout $side &&
+       for l in $one two three quatro
+       do
+               echo $l
+       done >file &&
+       git add file &&
+       test_tick &&
+       git commit -m $side &&
+       test_must_fail git merge $branch &&
+       for l in $one three four
+       do
+               echo $l
+       done >file &&
+       git add file &&
+       test_tick &&
+       git commit -m "merge $branch into $side"
+}
+
+verify_helper () {
+       it=$1 &&
+
+       # Ignore lines that were removed only from the other parent
+       sed -e '
+               1,/^@@@/d
+               /^ -/d
+               s/^\(.\)./\1/
+       ' "$it" >"$it.actual.1" &&
+       sed -e '
+               1,/^@@@/d
+               /^- /d
+               s/^.\(.\)/\1/
+       ' "$it" >"$it.actual.2" &&
+
+       git diff "$it^" "$it" -- | sed -e '1,/^@@/d' >"$it.expect.1" &&
+       test_cmp "$it.expect.1" "$it.actual.1" &&
+
+       git diff "$it^2" "$it" -- | sed -e '1,/^@@/d' >"$it.expect.2" &&
+       test_cmp "$it.expect.2" "$it.actual.2"
+}
+
+test_expect_success setup '
+       >file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+
+       git branch withone &&
+       git branch sansone &&
+
+       git checkout withone &&
+       setup_helper one withone sidewithone &&
+
+       git checkout sansone &&
+       setup_helper "" sansone sidesansone
+'
+
+test_expect_success 'check combined output (1)' '
+       git show sidewithone -- >sidewithone &&
+       verify_helper sidewithone
+'
+
+test_expect_failure 'check combined output (2)' '
+       git show sidesansone -- >sidesansone &&
+       verify_helper sidesansone
+'
+
+test_done
index f83322e..fac2093 100755 (executable)
@@ -148,4 +148,26 @@ do
        done
 done
 
+create_patch () {
+       sed -e "s/_/ /" <<-\EOF
+               diff --git a/target b/target
+               index e69de29..8bd6648 100644
+               --- a/target
+               +++ b/target
+               @@ -0,0 +1,3 @@
+               +An empty line follows
+               +
+               +A line with trailing whitespace and no newline_
+               \ No newline at end of file
+       EOF
+}
+
+test_expect_success 'trailing whitespace & no newline at the end of file' '
+       >target &&
+       create_patch >patch-file &&
+       git apply --whitespace=fix patch-file &&
+       grep "newline$" target &&
+       grep "^$" target
+'
+
 test_done
diff --git a/t/t4131-apply-fake-ancestor.sh b/t/t4131-apply-fake-ancestor.sh
new file mode 100755 (executable)
index 0000000..94373ca
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Stephen Boyd
+#
+
+test_description='git apply --build-fake-ancestor handling.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit 1 &&
+       test_commit 2 &&
+       mkdir sub &&
+       test_commit 3 sub/3 &&
+       test_commit 4
+'
+
+test_expect_success 'apply --build-fake-ancestor' '
+       git checkout 2 &&
+       echo "A" > 1.t &&
+       git diff > 1.patch &&
+       git reset --hard &&
+       git checkout 1 &&
+       git apply --build-fake-ancestor 1.ancestor 1.patch
+'
+
+test_expect_success 'apply --build-fake-ancestor in a subdirectory' '
+       git checkout 3 &&
+       echo "C" > sub/3.t &&
+       git diff > 3.patch &&
+       git reset --hard &&
+       git checkout 4 &&
+       (
+               cd sub &&
+               git apply --build-fake-ancestor 3.ancestor ../3.patch &&
+               test -f 3.ancestor
+       ) &&
+       git apply --build-fake-ancestor 3.ancestor 3.patch &&
+       test_cmp sub/3.ancestor 3.ancestor
+'
+
+test_done
index abb41b0..5f84b18 100755 (executable)
@@ -94,6 +94,10 @@ test_expect_success 'git archive with --output' \
     'git archive --output=b4.tar HEAD &&
     test_cmp b.tar b4.tar'
 
+test_expect_success 'git archive --remote' \
+    'git archive --remote=. HEAD >b5.tar &&
+    test_cmp b.tar b5.tar'
+
 test_expect_success \
     'validate file modification time' \
     'mkdir extract &&
index 5ec668d..e70246b 100755 (executable)
@@ -494,5 +494,15 @@ test_expect_success 'remote prune to cause a dangling symref' '
        grep "dangling symref" err
 '
 
+test_expect_success 'show empty remote' '
+
+       test_create_repo empty &&
+       git clone empty empty-clone &&
+       (
+               cd empty-clone &&
+               git remote show origin
+       )
+'
+
 test_done
 
index bee3424..d13c806 100755 (executable)
@@ -9,6 +9,11 @@ test_description='Per branch config variables affects "git fetch".
 
 D=`pwd`
 
+test_bundle_object_count () {
+       git verify-pack -v "$1" >verify.out &&
+       test "$2" = $(grep '^[0-9a-f]\{40\} ' verify.out | wc -l)
+}
+
 test_expect_success setup '
        echo >file original &&
        git add file &&
@@ -146,6 +151,7 @@ test_expect_success 'unbundle 1' '
        test_must_fail git fetch "$D/bundle1" master:master
 '
 
+
 test_expect_success 'bundle 1 has only 3 files ' '
        cd "$D" &&
        (
@@ -156,8 +162,7 @@ test_expect_success 'bundle 1 has only 3 files ' '
                cat
        ) <bundle1 >bundle.pack &&
        git index-pack bundle.pack &&
-       verify=$(git verify-pack -v bundle.pack) &&
-       test 4 = $(echo "$verify" | wc -l)
+       test_bundle_object_count bundle.pack 3
 '
 
 test_expect_success 'unbundle 2' '
@@ -180,7 +185,7 @@ test_expect_success 'bundle does not prerequisite objects' '
                cat
        ) <bundle3 >bundle.pack &&
        git index-pack bundle.pack &&
-       test 4 = $(git verify-pack -v bundle.pack | wc -l)
+       test_bundle_object_count bundle.pack 3
 '
 
 test_expect_success 'bundle should be able to create a full history' '
index f8942bc..7dcf391 100755 (executable)
@@ -54,6 +54,12 @@ deduxit me super semitas jusitiae,
 EOF
 printf "propter nomen suum." >> new4.txt
 
+test_expect_success 'merge with no changes' '
+       cp orig.txt test.txt &&
+       git merge-file test.txt orig.txt orig.txt &&
+       test_cmp test.txt orig.txt
+'
+
 cp new1.txt test.txt
 test_expect_success "merge without conflict" \
        "git merge-file test.txt orig.txt new2.txt"
index 2049ab6..42f6fff 100755 (executable)
@@ -208,4 +208,36 @@ test_expect_success 'merge-msg test #5-2' '
        test_cmp expected actual
 '
 
+test_expect_success 'merge-msg -F' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       setdate &&
+       git fetch . left right &&
+
+       git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'merge-msg -F in subdirectory' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       setdate &&
+       git fetch . left right &&
+       mkdir sub &&
+       cp .git/FETCH_HEAD sub/FETCH_HEAD &&
+       (
+               cd sub &&
+               git fmt-merge-msg -F FETCH_HEAD >../actual
+       ) &&
+       test_cmp expected actual
+'
+
 test_done
index b815937..7868af8 100755 (executable)
@@ -16,12 +16,13 @@ test_expect_success setup '
                echo foo mmap bar_mmap
                echo foo_mmap bar mmap baz
        } >file &&
+       echo ww w >w &&
        echo x x xx x >x &&
        echo y yy >y &&
        echo zzz > z &&
        mkdir t &&
        echo test >t/t &&
-       git add file x y z t/t &&
+       git add file x y z t/t &&
        test_tick &&
        git commit -m initial
 '
@@ -48,6 +49,12 @@ do
                diff expected actual
        '
 
+       test_expect_success "grep -w $L (w)" '
+               : >expected &&
+               ! git grep -n -w -e "^w" >actual &&
+               test_cmp expected actual
+       '
+
        test_expect_success "grep -w $L (x)" '
                {
                        echo ${HC}x:1:x x xx x
@@ -118,6 +125,36 @@ do
 
 done
 
+cat >expected <<EOF
+file:foo mmap bar_mmap
+EOF
+
+test_expect_success 'grep -e A --and -e B' '
+       git grep -e "foo mmap" --and -e bar_mmap >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+file:foo_mmap bar mmap
+file:foo_mmap bar mmap baz
+EOF
+
+
+test_expect_success 'grep ( -e A --or -e B ) --and -e B' '
+       git grep \( -e foo_ --or -e baz \) \
+               --and -e " mmap" >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+file:foo mmap bar
+EOF
+
+test_expect_success 'grep -e A --and --not -e B' '
+       git grep -e "foo mmap" --and --not -e bar_mmap >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'log grep setup' '
        echo a >>file &&
        test_tick &&
index bdb808a..ebfd34d 100755 (executable)
@@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' '
 
 '
 
+test_expect_success 'switch out of non-branch' '
+       git reset --hard master &&
+       git checkout master^0 &&
+       echo modified >one &&
+       test_must_fail git checkout renamer 2>error.log &&
+       ! grep "^Previous HEAD" error.log
+'
+
 test_done
index 5998baf..8eec0fa 100755 (executable)
@@ -183,4 +183,14 @@ test_expect_success 'commit message from stdin' '
        commit_msg_is "Log with foo word"
 '
 
+test_expect_success 'commit -F overrides -t' '
+       (
+               cd subdir &&
+               echo "-F log" > f.log &&
+               echo "-t template" > t.template &&
+               git commit --allow-empty -F f.log -t t.template
+       ) &&
+       commit_msg_is "-F log"
+'
+
 test_done
index 966bb0a..13c25f1 100755 (executable)
@@ -129,4 +129,19 @@ test_expect_success 'blame wholesale copy and more' '
 
 '
 
+test_expect_success 'blame path that used to be a directory' '
+       mkdir path &&
+       echo A A A A A >path/file &&
+       echo B B B B B >path/elif &&
+       git add path &&
+       test_tick &&
+       git commit -m "path was a directory" &&
+       rm -fr path &&
+       echo A A A A A >path &&
+       git add path &&
+       test_tick &&
+       git commit -m "path is a regular file" &&
+       git blame HEAD^.. -- path
+'
+
 test_done
index fcd5c26..9c1e21a 100755 (executable)
@@ -4,7 +4,7 @@ test_description='git blame encoding conversion'
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/t8005/utf8.txt
-. "$TEST_DIRECTORY"/t8005/cp1251.txt
+. "$TEST_DIRECTORY"/t8005/euc-japan.txt
 . "$TEST_DIRECTORY"/t8005/sjis.txt
 
 test_expect_success 'setup the repository' '
@@ -13,10 +13,10 @@ test_expect_success 'setup the repository' '
        git add file &&
        git commit --author "$UTF8_NAME <utf8@localhost>" -m "$UTF8_MSG" &&
 
-       echo "CP1251 LINE" >> file &&
+       echo "EUC-JAPAN LINE" >> file &&
        git add file &&
-       git config i18n.commitencoding cp1251 &&
-       git commit --author "$CP1251_NAME <cp1251@localhost>" -m "$CP1251_MSG" &&
+       git config i18n.commitencoding eucJP &&
+       git commit --author "$EUC_JAPAN_NAME <euc-japan@localhost>" -m "$EUC_JAPAN_MSG" &&
 
        echo "SJIS LINE" >> file &&
        git add file &&
@@ -41,17 +41,17 @@ test_expect_success \
 '
 
 cat >expected <<EOF
-author $CP1251_NAME
-summary $CP1251_MSG
-author $CP1251_NAME
-summary $CP1251_MSG
-author $CP1251_NAME
-summary $CP1251_MSG
+author $EUC_JAPAN_NAME
+summary $EUC_JAPAN_MSG
+author $EUC_JAPAN_NAME
+summary $EUC_JAPAN_MSG
+author $EUC_JAPAN_NAME
+summary $EUC_JAPAN_MSG
 EOF
 
 test_expect_success \
        'blame respects i18n.logoutputencoding' '
-       git config i18n.logoutputencoding cp1251 &&
+       git config i18n.logoutputencoding eucJP &&
        git blame --incremental file | \
                egrep "^(author|summary) " > actual &&
        test_cmp actual expected
@@ -76,8 +76,8 @@ test_expect_success \
 cat >expected <<EOF
 author $SJIS_NAME
 summary $SJIS_MSG
-author $CP1251_NAME
-summary $CP1251_MSG
+author $EUC_JAPAN_NAME
+summary $EUC_JAPAN_MSG
 author $UTF8_NAME
 summary $UTF8_MSG
 EOF
diff --git a/t/t8005/euc-japan.txt b/t/t8005/euc-japan.txt
new file mode 100644 (file)
index 0000000..288f040
--- /dev/null
@@ -0,0 +1,2 @@
+EUC_JAPAN_NAME="»³ÅÄ ÂÀϺ"
+EUC_JAPAN_MSG="¥Ö¥ì¡¼¥à¤Î¥Æ¥¹¥È¤Ç¤¹¡£"
index 2ccfbad..bbdefea 100644 (file)
@@ -1,2 +1,2 @@
-SJIS_NAME="\84I\84r\84p\84\84P\84u\84\84\84\82\84\80\84r\84y\84\89 \84R\84y\84t\84\80\84\82\84\80\84r"
-SJIS_MSG="\84S\84u\84\83\84\84\84\80\84r\84\80\84\84\83\84\80\84\80\84q\84\8b\84u\84~\84y\84u"
+SJIS_NAME="\8eR\93\91¾\98Y"
+SJIS_MSG="\83u\83\8c\81[\83\80\82Ì\83e\83X\83g\82Å\82·\81B"
index f46cfc5..4d00dbe 100644 (file)
@@ -1,2 +1,2 @@
-UTF8_NAME="Иван Петрович Сидоров"
-UTF8_MSG="Тестовое сообщение"
+UTF8_NAME="山田 太郎"
+UTF8_MSG="ブレームのテストです。"
index 0e49279..0ba6207 100755 (executable)
@@ -7,7 +7,7 @@
 #
 # To enable this hook, rename this file to "pre-commit".
 
-if git-rev-parse --verify HEAD 2>/dev/null
+if git-rev-parse --verify HEAD >/dev/null 2>&1
 then
        against=HEAD
 else
index 3dfb03c..efecb65 100644 (file)
@@ -1069,7 +1069,7 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs)
 void transport_unlock_pack(struct transport *transport)
 {
        if (transport->pack_lockfile) {
-               unlink(transport->pack_lockfile);
+               unlink_or_warn(transport->pack_lockfile);
                free(transport->pack_lockfile);
                transport->pack_lockfile = NULL;
        }
index e4eb8fa..a0697d2 100644 (file)
@@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce)
 {
        if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
                return;
-       if (unlink(ce->name))
+       if (unlink_or_warn(ce->name))
                return;
        schedule_dir_for_removal(ce->name, ce_namelen(ce));
 }
@@ -982,7 +982,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
                return error("Cannot do a oneway merge of %d trees",
                             o->merge_size);
 
-       if (!a)
+       if (!a || a == o->df_conflict_entry)
                return deleted_entry(old, old, o);
 
        if (old && same(old, a)) {
index d556da9..57529ae 100644 (file)
@@ -13,7 +13,8 @@ PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$",
         "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"),
 PATTERNS("java",
         "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
-        "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
+        "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
+        /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
         "|[-+*/<>%&^|=!]="
@@ -25,7 +26,7 @@ PATTERNS("objc",
         /* Objective-C methods */
         "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
         /* C functions */
-        "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n"
+        "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$\n"
         /* Objective-C class/protocol definitions */
         "^(@(implementation|interface|protocol)[ \t].*)$",
         /* -- */
index d8efb13..7eb3218 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -289,3 +289,19 @@ int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
        safe_create_leading_directories(name);
        return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
 }
+
+int unlink_or_warn(const char *file)
+{
+       int rc = unlink(file);
+
+       if (rc < 0) {
+               int err = errno;
+               if (ENOENT != err) {
+                       warning("unable to unlink %s: %s",
+                               file, strerror(errno));
+                       errno = err;
+               }
+       }
+       return rc;
+}
+
diff --git a/ws.c b/ws.c
index b1efcd9..59d0883 100644 (file)
--- a/ws.c
+++ b/ws.c
 static struct whitespace_rule {
        const char *rule_name;
        unsigned rule_bits;
+       unsigned loosens_error;
 } whitespace_rule_names[] = {
-       { "trailing-space", WS_TRAILING_SPACE },
-       { "space-before-tab", WS_SPACE_BEFORE_TAB },
-       { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB },
-       { "cr-at-eol", WS_CR_AT_EOL },
+       { "trailing-space", WS_TRAILING_SPACE, 0 },
+       { "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
+       { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
+       { "cr-at-eol", WS_CR_AT_EOL, 1 },
 };
 
 unsigned parse_whitespace_rule(const char *string)
@@ -79,7 +80,8 @@ unsigned whitespace_rule(const char *pathname)
                        unsigned all_rule = 0;
                        int i;
                        for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
-                               all_rule |= whitespace_rule_names[i].rule_bits;
+                               if (!whitespace_rule_names[i].loosens_error)
+                                       all_rule |= whitespace_rule_names[i].rule_bits;
                        return all_rule;
                } else if (ATTR_FALSE(value)) {
                        /* false (-whitespace) */
@@ -259,12 +261,11 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
        /*
         * Strip trailing whitespace
         */
-       if ((ws_rule & WS_TRAILING_SPACE) &&
-           (2 <= len && isspace(src[len-2]))) {
-               if (src[len - 1] == '\n') {
+       if (ws_rule & WS_TRAILING_SPACE) {
+               if (0 < len && src[len - 1] == '\n') {
                        add_nl_to_tail = 1;
                        len--;
-                       if (1 < len && src[len - 1] == '\r') {
+                       if (0 < len && src[len - 1] == '\r') {
                                add_cr_to_tail = !!(ws_rule & WS_CR_AT_EOL);
                                len--;
                        }
index d9737f0..1cb65a9 100644 (file)
@@ -563,23 +563,22 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                return -1;
        }
        status = 0;
-       if (xscr1 || xscr2) {
-               if (!xscr1) {
-                       result->ptr = xdl_malloc(mf2->size);
-                       memcpy(result->ptr, mf2->ptr, mf2->size);
-                       result->size = mf2->size;
-               } else if (!xscr2) {
-                       result->ptr = xdl_malloc(mf1->size);
-                       memcpy(result->ptr, mf1->ptr, mf1->size);
-                       result->size = mf1->size;
-               } else {
-                       status = xdl_do_merge(&xe1, xscr1, name1,
-                                             &xe2, xscr2, name2,
-                                             flags, xpp, result);
-               }
-               xdl_free_script(xscr1);
-               xdl_free_script(xscr2);
+       if (!xscr1) {
+               result->ptr = xdl_malloc(mf2->size);
+               memcpy(result->ptr, mf2->ptr, mf2->size);
+               result->size = mf2->size;
+       } else if (!xscr2) {
+               result->ptr = xdl_malloc(mf1->size);
+               memcpy(result->ptr, mf1->ptr, mf1->size);
+               result->size = mf1->size;
+       } else {
+               status = xdl_do_merge(&xe1, xscr1, name1,
+                                     &xe2, xscr2, name2,
+                                     flags, xpp, result);
        }
+       xdl_free_script(xscr1);
+       xdl_free_script(xscr2);
+
        xdl_free_env(&xe1);
        xdl_free_env(&xe2);